¿Cuál es la forma más concisa de leer los parámetros de consulta en AngularJS?

312

Me gustaría leer los valores de los parámetros de consulta de URL utilizando AngularJS. Estoy accediendo al HTML con la siguiente URL:

http://127.0.0.1:8080/test.html?target=bob

Como se esperaba, location.searches "?target=bob". Para acceder al valor de target , he encontrado varios ejemplos enumerados en la web, pero ninguno de ellos funciona en AngularJS 1.0.0rc10. En particular, los siguientes son todos undefined:

  • $location.search.target
  • $location.search['target']
  • $location.search()['target']

Alguien sabe lo que funcionará? (Estoy usando $locationcomo parámetro para mi controlador)


Actualizar:

He publicado una solución a continuación, pero no estoy completamente satisfecho con ella. La documentación en la Guía del desarrollador: Servicios angulares: el uso de $ location establece lo siguiente sobre $location:

¿Cuándo debo usar $ location?

Cada vez que su aplicación necesite reaccionar a un cambio en la URL actual o si desea cambiar la URL actual en el navegador.

Para mi escenario, mi página se abrirá desde una página web externa con un parámetro de consulta, por lo que no estoy "reaccionando a un cambio en la URL actual" per se. Entonces, tal vez $locationno sea la herramienta adecuada para el trabajo (para los detalles feos, vea mi respuesta a continuación). Por lo tanto, he cambiado el título de esta pregunta de "¿Cómo leer los parámetros de consulta en AngularJS usando $ location?" a "¿Cuál es la forma más concisa de leer los parámetros de consulta en AngularJS?". Obviamente, podría usar JavaScript y expresiones regulares para analizar location.search, pero ir a ese nivel bajo para algo tan básico realmente ofende la sensibilidad de mi programador.

Entonces: ¿hay una mejor manera de usar $locationque yo en mi respuesta, o hay una alternativa concisa?

Ellis Whitehead
fuente
1
¿No debería funcionar $ location.search () ['target']?
robar el
Esto no funciona, porque no hay hash después del camino. http://127.0.0.1:8080/test.html#?target=bobfuncionaría, observe el #antes de la ?. $locationes un método de enrutamiento de segundo nivel que no se envía al servidor.
Daniel F
1
@DanielF @rob, ambos tienen razón. $location.search()['target']funciona después de $locationProvider.html5Mode(true)haber sido llamado en un navegador moderno.
krispy

Respuestas:

199

Puede inyectar $ routeParams (requiere ngRoute ) en su controlador. Aquí hay un ejemplo de los documentos:

// Given:
// URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
// Route: /Chapter/:chapterId/Section/:sectionId
//
// Then
$routeParams ==> {chapterId:1, sectionId:2, search:'moby'}

EDITAR: También puede obtener y establecer parámetros de consulta con el servicio $ location (disponible en ng), particularmente su searchmétodo: $ location.search () .

$ routeParams son menos útiles después de la carga inicial del controlador; $location.search()Se puede llamar en cualquier momento.

Andrew Joslin
fuente
1
Gracias por la sugerencia y enlace! Leí la página y también intenté configurar una muestra de trabajo. Sin embargo, el enfoque no funcionará para mí, porque realmente no quiero usar el enrutamiento en este caso. Sin embargo, esta fue una sugerencia útil, y la votaré una vez que tenga suficiente representante de stackoverflow.
Ellis Whitehead
1
Yo diría que la respuesta de @ pkozlowski.opensource es más precisa en esta situación
Martín Coll
2
No del todo ... los parámetros de consulta se incluyen en el objeto $ routeParams con los parámetros de ruta normales. y puedes leerlos / configurarlos con $ location.search (). Agregaré eso a la respuesta.
Andrew Joslin
55
Jakub tiene razón. Son cosas diferentes. Cuando utiliza la "búsqueda" en angular, agrega la consulta al hash (final de la URL). La especificación de RFC para URI establece que los parámetros de consulta deben anteponer (no anexar) el hash. Así, la "búsqueda" es una construcción que solo angular extrapolará e interpretará. Esta es la razón por la que solo el modo HTML5 funcionará para la solución anterior, porque está delegando todas las solicitudes en una página (a nivel del servidor) independientemente del URI real.
Steven Pena
2
¡esto solo funciona si quieres usar route en angularJS!
windmaomao
189

Es bueno que hayas logrado que funcione con el modo html5, pero también es posible hacerlo funcionar en el modo hashbang.

Simplemente podrías usar:

$location.search().target

para acceder al parámetro de búsqueda 'objetivo'.

Para la referencia, aquí está el jsFiddle de trabajo: http://web.archive.org/web/20130317065234/http://jsfiddle.net/PHnLb/7/

var myApp = angular.module('myApp', []);

function MyCtrl($scope, $location) {

    $scope.location = $location;
    $scope.$watch('location.search()', function() {
        $scope.target = ($location.search()).target;
    }, true);

    $scope.changeTarget = function(name) {
        $location.search('target', name);
    }
}
<div ng-controller="MyCtrl">

    <a href="#!/test/?target=Bob">Bob</a>
    <a href="#!/test/?target=Paul">Paul</a>
    
    <hr/>    
    URL 'target' param getter: {{target}}<br>
    Full url: {{location.absUrl()}}
    <hr/>
    
    <button ng-click="changeTarget('Pawel')">target=Pawel</button>
    
</div>

pkozlowski.opensource
fuente
2
¿necesitas paréntesis alrededor de $ location.search ()?
Magne
2
@Magne: sí, es necesario paréntesis, $ location.search es un método docs.angularjs.org/api/ng/service/$location
nandin
44
No olvide que si no usa HTML5Mode(true), solo los parámetros después de # / están disponibles o se agregan a la url con # / al principio.
Sebastian
21
@nandin: No, usted no necesita los paréntesis alrededor $location.search() . No estoy seguro de por qué esta respuesta los pone allí.
Dan Tao
99
Siento que @nandin no entendió la pregunta "¿Necesita paréntesis?". Usted lo necesita los paréntesis después de la búsqueda, pero no los que alrededor de la totalidad de $location.search().
K. Carpenter
56

Para dar una respuesta parcial a mi propia pregunta, aquí hay una muestra de trabajo para navegadores HTML5:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <script src="http://code.angularjs.org/1.0.0rc10/angular-1.0.0rc10.js"></script>
  <script>
    angular.module('myApp', [], function($locationProvider) {
      $locationProvider.html5Mode(true);
    });
    function QueryCntl($scope, $location) {
      $scope.target = $location.search()['target'];
    }
  </script>
</head>
<body ng-controller="QueryCntl">

Target: {{target}}<br/>

</body>
</html>

La clave era llamar $locationProvider.html5Mode(true);como se hizo anteriormente. Ahora funciona al abrir http://127.0.0.1:8080/test.html?target=bob. No estoy contento con el hecho de que no funcionará en navegadores antiguos, pero podría usar este enfoque de todos modos.

Una alternativa que funcionaría con los navegadores más antiguos sería abandonar la html5mode(true)llamada y usar la siguiente dirección con hash + barra diagonal:

http://127.0.0.1:8080/test.html#/?target=bob

La documentación relevante se encuentra en la Guía del desarrollador: Servicios angulares: Uso de $ location (extraño que mi búsqueda en Google no haya encontrado esto ...).

Ellis Whitehead
fuente
Gracias por esto. He estado tirando de mi pelo tratando de leer en los parámetros de consulta. Seguí siendo 'indefinido' como mencionaste anteriormente. Establecer modo a html5 funcionó.
sthomps
¿No debería el ng-controlleratributo de <body>ajustarse a MyApp?
Jago
44
Parece que comienza con Angular 1.3, para usar html5Mode también necesita agregar una <base href="https://stackoverflow.com/" />etiqueta o agregar requireBase: falsecomo otro parámetro a la llamada a html5Mode. Detalles aquí
dae721
17

Se puede hacer de dos maneras:

  1. Utilizando $routeParams

La mejor solución recomendada es usarla $routeParamsen su controlador. Requiere ngRouteque se instale el módulo.

   function MyController($scope, $routeParams) {
      // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
      // Route: /Chapter/:chapterId/Section/:sectionId
      // $routeParams ==> {chapterId:'1', sectionId:'2', search:'moby'}
      var search = $routeParams.search;
  }
  1. Utilizando $location.search().

Hay una advertencia aquí. Solo funcionará con el modo HTML5. Por defecto, no funciona para la URL que no tiene hash ( #)http://localhost/test?param1=abc&param2=def

Puede hacerlo funcionar agregando #/la URL.http://localhost/test#/?param1=abc&param2=def

$location.search() para devolver un objeto como:

{
  param1: 'abc',
  param2: 'def'
}
Fizer Khan
fuente
55
Gracias por su consejo con # /
yonexbat
9

$ location.search () funcionará solo con el modo HTML5 activado y solo en el navegador compatible.

Esto funcionará siempre:

$ window.location.search

Illidan
fuente
6

Solo para veranear.

Si su aplicación se está cargando desde enlaces externos, entonces angular no detectará esto como un cambio de URL, por lo que $ loaction.search () le dará un objeto vacío. Para resolver esto, debe establecer lo siguiente en la configuración de su aplicación (app.js)

.config(['$routeProvider', '$locationProvider', function ($routeProvider,     $locationProvider) 
{
   $routeProvider
      .when('/', {
         templateUrl: 'views/main.html',
         controller: 'MainCtrl'
      })
      .otherwise({
         redirectTo: '/'
      });

      $locationProvider.html5Mode(true);
 }]);
sapy
fuente
1
Sí. Fue un dolor encontrarlo. Gracias por el comentario.
mikeborgh
2

Solo una precisión a la respuesta de Ellis Whitehead. $locationProvider.html5Mode(true);no funcionará con la nueva versión de angularjs sin especificar la URL base para la aplicación con una <base href="">etiqueta o establecer el parámetro requireBaseenfalse

Del documento :

Si configura $ location para usar html5Mode (history.pushState), debe especificar la URL base para la aplicación con una etiqueta o configurar $ locationProvider para que no requiera una etiqueta base pasando un objeto de definición con requireBase: false a $ locationProvider. html5Mode ():

$locationProvider.html5Mode({
  enabled: true,
  requireBase: false
});
S. Thiongane
fuente
1

también puede usar $ location. $$ search.yourparameter

thewindev
fuente
18
El $$searches una variable interna, cuyo uso no es una buena idea.
kumarharsh
1

esto puede ayudarte

¿Cuál es la forma más concisa de leer los parámetros de consulta en AngularJS?

// Given:
// URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
// Route: /Chapter/:chapterId/Section/:sectionId
//
// Then
$routeParams ==> {chapterId:1, sectionId:2, search:'moby'}

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <script src="http://code.angularjs.org/1.0.0rc10/angular-1.0.0rc10.js"></script>
  <script>
    angular.module('myApp', [], function($locationProvider) {
      $locationProvider.html5Mode(true);
    });
    function QueryCntl($scope, $location) {
      $scope.target = $location.search()['target'];
    }
  </script>
</head>
<body ng-controller="QueryCntl">

Target: {{target}}<br/>

</body>
</html>

($location.search()).target
Krishna
fuente
1

Encontré que para un SPA HTML5Mode causa muchos problemas de error 404, y no es necesario hacer que $ location.search funcione en este caso. En mi caso, quiero capturar un parámetro de cadena de consulta de URL cuando un usuario visita mi sitio, independientemente de la "página" a la que se vincule inicialmente, Y poder enviarlos a esa página una vez que inicien sesión. Así que simplemente capturo todos esas cosas en app.run

$rootScope.$on('$stateChangeStart', function (e, toState, toParams, fromState, fromParams) {
    if (fromState.name === "") {
        e.preventDefault();
        $rootScope.initialPage = toState.name;
        $rootScope.initialParams = toParams;
        return;
    }
    if ($location.search().hasOwnProperty('role')) {
        $rootScope.roleParameter = $location.search()['role'];
    }
    ...
}

luego, después de iniciar sesión, puedo decir $ state.go ($ rootScope.initialPage, $ rootScope.initialParams)

nuander
fuente
-3

Es un poco tarde, pero creo que tu problema fue tu URL. Si en lugar de

http://127.0.0.1:8080/test.html?target=bob

tu tenias

http://127.0.0.1:8080/test.html#/?target=bob

Estoy bastante seguro de que hubiera funcionado. Angular es muy exigente con su # /

Octavio Kidd
fuente
Eso es solo si no está habilitando el modo HTML5. El # / no siempre está ahí en las URL angulares.
LocalPCGuy
Es si estás construyendo un SPA. Todas mis URL tienen un #. Y HTML5Mode significa 1) 404 en la actualización de la página y 2) las URL directas no funcionarán. Parece un alto precio a pagar.
nuander