Quelle est la façon la plus concise de lire les paramètres de requête dans AngularJS?

312

Je voudrais lire les valeurs des paramètres de requête URL à l'aide d'AngularJS. J'accède au HTML avec l'URL suivante:

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

Comme prévu, location.searchc'est "?target=bob". Pour accéder à la valeur de target , j'ai trouvé divers exemples répertoriés sur le Web, mais aucun ne fonctionne dans AngularJS 1.0.0rc10. En particulier, les éléments suivants sont tous undefined:

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

Quelqu'un sait ce qui fonctionnera? (J'utilise $locationcomme paramètre pour mon contrôleur)


Mettre à jour:

J'ai posté une solution ci-dessous, mais je n'en suis pas entièrement satisfait. La documentation du Guide du développeur: Services angulaires: Utilisation de $ location indique ce qui suit $location:

Quand dois-je utiliser $ location?

Chaque fois que votre application doit réagir à une modification de l'URL actuelle ou si vous souhaitez modifier l'URL actuelle dans le navigateur.

Pour mon scénario, ma page sera ouverte à partir d'une page Web externe avec un paramètre de requête, donc je ne "réagis pas à un changement de l'URL actuelle" en soi. Ce $locationn'est peut - être pas le bon outil pour le travail (pour les moindres détails, voir ma réponse ci-dessous). J'ai donc changé le titre de cette question de "Comment lire les paramètres de requête dans AngularJS en utilisant $ location?" à "Quelle est la manière la plus concise de lire les paramètres de requête dans AngularJS?". Évidemment, je pourrais simplement utiliser javascript et l'expression régulière pour analyser location.search, mais aller à ce niveau bas pour quelque chose de si basique offense vraiment mes sensibilités de programmeur.

Donc: y a-t-il une meilleure façon d'utiliser $locationque je fais dans ma réponse, ou y a-t-il une alternative concise?

Ellis Whitehead
la source
1
$ Location.search () ['target'] ne devrait-il pas fonctionner?
voler
Cela ne fonctionne pas, car il n'y a pas de hachage après le chemin. http://127.0.0.1:8080/test.html#?target=bobfonctionnerait, notez le #avant le ?. $locationest une méthode de routage de deuxième niveau qui n'est pas envoyée au serveur.
Daniel F
1
@DanielF @rob, vous avez tous les deux raison. $location.search()['target']fonctionne après $locationProvider.html5Mode(true)avoir été appelé dans un navigateur moderne.
krispy

Réponses:

199

Vous pouvez injecter $ routeParams (nécessite ngRoute ) dans votre contrôleur. Voici un exemple tiré de la documentation:

// 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'}

EDIT: Vous pouvez également obtenir et définir des paramètres de requête avec le service $ location (disponible en ng), en particulier sa searchméthode: $ location.search () .

$ routeParams sont moins utiles après la charge initiale du contrôleur; $location.search()peut être appelé à tout moment.

Andrew Joslin
la source
1
Merci pour la suggestion et le lien! J'ai lu la page et j'ai également tenté de créer un échantillon de travail. Cependant, l'approche ne fonctionnera pas pour moi, car je ne veux vraiment pas utiliser le routage dans ce cas. C'était néanmoins une suggestion utile, et je voterai une fois que j'aurai suffisamment de représentants stackoverflow.
Ellis Whitehead
1
Je dirais que la réponse de @ pkozlowski.opensource est plus précise dans cette situation
Martín Coll
2
Pas tout à fait. Les paramètres de requête sont inclus dans l'objet $ routeParams avec les paramètres de route normaux. et vous pouvez les lire / les définir avec $ location.search (). J'ajouterai cela à la réponse.
Andrew Joslin
5
Jakub a raison. Ce sont des choses différentes. Lorsque vous utilisez la "recherche" en angulaire, elle ajoute la requête au hachage (fin de l'URL). La spécification RFC pour l'URI indique que les paramètres de requête doivent ajouter (et non ajouter) le hachage. Ainsi, la «recherche» est une construction que seule l'angulaire extrapolera et interprétera. C'est pourquoi seul le mode HTML5 fonctionnera pour la solution ci-dessus, car vous déléguez toutes les demandes à une page (au niveau du serveur), quel que soit l'URI réel.
Steven Pena
2
cela ne fonctionne que si vous souhaitez utiliser route dans angularJS!
windmaomao
189

Heureusement que vous avez réussi à le faire fonctionner avec le mode html5 mais il est également possible de le faire fonctionner en mode hashbang.

Vous pouvez simplement utiliser:

$location.search().target

pour accéder au paramètre de recherche «cible».

Pour la référence, voici le jsFiddle de travail: 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
la source
2
avez-vous besoin des parenthèses autour de $ location.search ()?
Magne
2
@Magne: oui, vous avez besoin de parenthèses, $ location.search est une méthode docs.angularjs.org/api/ng/service/$location
nandin
4
N'oubliez pas que si vous n'utilisez pas, HTML5Mode(true)seuls les paramètres après # / sont disponibles ou sont ajoutés à l'url avec # / au début.
Sebastian
21
@nandin: Non, vous ne pas besoin des parenthèses autour $location.search() . Je ne sais pas pourquoi cette réponse les y met.
Dan Tao
9
J'ai l'impression que @nandin a mal compris la question "Avez-vous besoin de parenthèses". Vous ne devez les parenthèses après la recherche, mais pas ceux autour de l'ensemble de $location.search().
K. Carpenter
56

Pour donner une réponse partielle à ma propre question, voici un exemple de travail pour les navigateurs 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 clé était d'appeler $locationProvider.html5Mode(true);comme ci-dessus. Cela fonctionne maintenant lors de l'ouverture http://127.0.0.1:8080/test.html?target=bob. Je ne suis pas satisfait du fait que cela ne fonctionnera pas dans les anciens navigateurs, mais je pourrais utiliser cette approche de toute façon.

Une alternative qui fonctionnerait avec des navigateurs plus anciens serait de supprimer l' html5mode(true)appel et d'utiliser à la place l'adresse suivante avec hachage + barre oblique:

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

La documentation pertinente se trouve dans le Guide du développeur: Services angulaires: Utilisation de $ location (étrange que ma recherche Google n'ait pas trouvé cela ...).

Ellis Whitehead
la source
Merci pour cela. J'ai tiré mes cheveux en essayant de lire les paramètres de la requête. Vous avez continué à être «non défini» comme vous l'avez mentionné ci-dessus. Le réglage du mode sur html5 a fonctionné.
sthomps
L' ng-controllerattribut de ne doit-il pas <body>être défini sur MyApp?
Jago
4
Il semble que vous commenciez par Angular 1.3, pour utiliser html5Mode, vous devez également ajouter une <base href="https://stackoverflow.com/" />balise ou ajouter requireBase: falseun autre paramètre à l'appel à html5Mode. Détails ici
dae721
17

Cela peut se faire de deux manières:

  1. En utilisant $routeParams

La meilleure solution recommandée est d'utiliser $routeParamsdans votre contrôleur. Il nécessite que le ngRoutemodule soit installé.

   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. Utilisation $location.search().

Il y a une mise en garde ici. Cela ne fonctionnera qu'avec le mode HTML5. Par défaut, cela ne fonctionne pas pour l'URL qui ne contient pas de hachage ( #)http://localhost/test?param1=abc&param2=def

Vous pouvez le faire fonctionner en ajoutant #/l'URL.http://localhost/test#/?param1=abc&param2=def

$location.search() pour retourner un objet comme:

{
  param1: 'abc',
  param2: 'def'
}
Fizer Khan
la source
5
Merci pour vos conseils avec # /
yonexbat
9

$ location.search () ne fonctionnera qu'avec le mode HTML5 activé et uniquement sur le navigateur compatible.

Cela fonctionnera toujours:

$ window.location.search

Illidan
la source
6

Juste pour résumer.

Si votre application est chargée à partir de liens externes, angular ne détectera pas cela comme un changement d'URL, donc $ loaction.search () vous donnera un objet vide. Pour résoudre ce problème, vous devez définir ce qui suit dans la configuration de votre application (app.js)

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

      $locationProvider.html5Mode(true);
 }]);
saveur
la source
1
Oui. C'était une douleur à trouver. Merci pour le commentaire.
mikeborgh
2

Juste une précision à la réponse d'Ellis Whitehead. $locationProvider.html5Mode(true);ne fonctionnera pas avec la nouvelle version d'angularjs sans spécifier l'URL de base de l'application avec une <base href="">balise ou définir le paramètre requireBasesurfalse

Du doc :

Si vous configurez $ location pour utiliser html5Mode (history.pushState), vous devez spécifier l'URL de base de l'application avec une balise ou configurer $ locationProvider pour ne pas avoir besoin d'une balise de base en passant un objet de définition avec requireBase: false à $ locationProvider. html5Mode ():

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

vous pouvez également utiliser $ location. $$ search.yourparameter

thewindev
la source
18
Il $$searchs'agit d'une variable interne dont l'utilisation n'est pas une si bonne idée.
kumarharsh
1

cela peut vous aider

Quelle est la façon la plus concise de lire les paramètres de requête dans 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
la source
1

J'ai trouvé que pour un SPA HTML5Mode provoque beaucoup de problèmes d'erreur 404, et il n'est pas nécessaire de faire fonctionner $ location.search dans ce cas. Dans mon cas, je veux capturer un paramètre de chaîne de requête d'URL lorsqu'un utilisateur arrive sur mon site, quelle que soit la "page" vers laquelle il se connecte initialement, ET pouvoir les envoyer à cette page une fois connecté. Je capture donc tout ce genre de choses dans 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'];
    }
    ...
}

puis plus tard après la connexion, je peux dire $ state.go ($ rootScope.initialPage, $ rootScope.initialParams)

nuander
la source
-3

C'est un peu tard, mais je pense que votre problème était votre URL. Si au lieu de

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

tu avais

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

Je suis presque sûr que cela aurait fonctionné. Angular est vraiment pointilleux sur son # /

Octavio Kidd
la source
Ce n'est que si vous n'activez pas le mode HTML5. Le # / n'est pas toujours présent dans les URL angulaires.
LocalPCGuy
C'est si vous construisez un SPA. Toutes mes URL ont un #. Et HTML5Mode signifie 1) 404 sur l'actualisation de la page et 2) les URL directes ne fonctionneront pas. On dirait un prix élevé à payer.
nuander