`ui-router` $ stateParams contre $ state.params

116

Avec ui-router, il est possible d'injecter l'un $stateou l' autre $stateParamsdans un contrôleur pour accéder aux paramètres de l'URL. Cependant, l'accès aux paramètres via $stateParamsn'expose que les paramètres appartenant à l'état géré par le contrôleur qui y accède, ainsi qu'à ses états parents, alors qu'il $state.paramscontient tous les paramètres, y compris ceux de n'importe quel état enfant.

Compte tenu du code suivant, si nous chargeons directement l'URL http://path/1/paramA/paramB, voici comment cela se passe lorsque les contrôleurs se chargent:

$stateProvider.state('a', {
     url: 'path/:id/:anotherParam/',
     controller: 'ACtrl',
  });

$stateProvider.state('a.b', {
     url: '/:yetAnotherParam',
     controller: 'ABCtrl',
  });

module.controller('ACtrl', function($stateParams, $state) {
   $state.params; // has id, anotherParam, and yetAnotherParam
   $stateParams;  // has id and anotherParam
}

module.controller('ABCtrl', function($stateParams, $state) {
   $state.params; // has id, anotherParam, and yetAnotherParam
   $stateParams;  // has id, anotherParam, and yetAnotherParam
}

La question est, pourquoi la différence? Et existe-t-il des directives sur les meilleures pratiques concernant quand et pourquoi vous devriez utiliser ou éviter d'utiliser l'un ou l'autre?

Merott
la source
Une question si parfaitement illustrée - merci de me dire même ce que j'essayais de demander!
Peter Nixey

Réponses:

65

La documentation réitère vos conclusions ici: https://github.com/angular-ui/ui-router/wiki/URL-Routing#stateparams-service

Si ma mémoire $stateParamsest $state.paramsbonne , a été introduit plus tard que l'original , et semble être un simple injecteur d'aide pour éviter d'écrire en continu $state.params.

Je doute qu'il y ait des lignes directrices sur les meilleures pratiques, mais le contexte l'emporte pour moi. Si vous souhaitez simplement accéder aux paramètres reçus dans l'url, utilisez $stateParams. Si vous voulez savoir quelque chose de plus complexe sur l'état lui-même, utilisez $state.

Matt Way
la source
1
Je me suis retrouvé à utiliser $state.paramsin ACtrl, car je voulais vérifier si yetAnotherParamc'était défini. Si ce n'est pas le cas, je peux faire quelque chose. Je n'entrerai pas dans les détails de ce quelque chose, car cela pourrait justifier une question en soi. Cependant, je pense que je peux faire un hack en recherchant un paramètre qui est introduit par un état enfant et non reconnu par l'état actuel via $stateParams. J'ai trouvé une approche alternative depuis.
Merott
3
En fait, la différence entre les deux est plus qu'une simple question de contexte. $ stateParams capture les paramètres basés sur les URL que $ state considère comme applicables à cet état, même si son état enfant contient plus de paramètres . $ state.params semble capturer tous les paramètres url + non-url de l' état actuel dans lequel vous vous trouvez. Si vous êtes dans l'état parent.child, alors $stateParamsdansparentController évaluera les paramètres basés sur l'url de parent, mais pas ceux de parent.child. Consultez ce numéro .
Amy.js
1
D'un autre côté, $ stateParams peut conserver des objets personnalisés, des types, etc. tandis que $ state.params "convertirait des objets personnalisés en objets simples".
Amy.js
2
$stateParamsfonctionne dans la résolution, alors que $state.paramsc'est incorrect (ne montre pas les paramètres pour l'état qui n'est pas encore résolu)
karaxuna
1
J'ai trouvé que le scope peut $ regarder $ state.params, mais pas $ stateParams. Je ne sais pas pourquoi.
weltschmerz
19

Une autre raison d'utiliser $state.paramsest l'état non basé sur une URL, qui (à mon avis) est malheureusement sous-documenté et très puissant.

Je viens de découvrir cela en cherchant sur Google comment transmettre l'état sans avoir à l'exposer dans l'URL et j'ai répondu à une question ailleurs sur SO.

En gros, cela permet ce type de syntaxe:

<a ui-sref="toState(thingy)" class="list-group-item" ng-repeat="thingy in thingies">{{ thingy.referer }}</a>
brun
la source
Salut bbrown, d'une manière ou d'une autre, je ne peux pas le faire fonctionner, avez-vous un exemple fonctionnel?
storm_buster
14

EDIT: Cette réponse est correcte pour la version 0.2.10. Comme @Alexander Vasilyev l'a souligné, cela ne fonctionne pas dans la version0.2.14 .

Une autre raison à utiliser $state.paramsest lorsque vous devez extraire des paramètres de requête comme celui-ci:

$stateProvider.state('a', {
  url: 'path/:id/:anotherParam/?yetAnotherParam',
  controller: 'ACtrl',
});

module.controller('ACtrl', function($stateParams, $state) {
  $state.params; // has id, anotherParam, and yetAnotherParam
  $stateParams;  // has id and anotherParam
}
Daerin
la source
2
Plus applicable. Voir Plunker: plnkr.co/edit/r2JhV4PcYpKJdBCwHIWS?p=preview
Alexander Vasilyev
4

Il existe de nombreuses différences entre les deux. Mais en travaillant pratiquement, j'ai trouvé cela en utilisant $state.paramsmieux. Lorsque vous utilisez de plus en plus de paramètres, cela peut être difficile à gérer $stateParams. où si nous utilisons plusieurs paramètres qui ne sont pas des paramètres d'URL $stateest très utile

 .state('shopping-request', {
      url: '/shopping-request/{cartId}',
      data: {requireLogin: true},
      params : {role: null},
      views: {
        '': {templateUrl: 'views/templates/main.tpl.html', controller: "ShoppingRequestCtrl"},
        'body@shopping-request': {templateUrl: 'views/shops/shopping-request.html'},
        'footer@shopping-request': {templateUrl: 'views/templates/footer.tpl.html'},
        'header@shopping-request': {templateUrl: 'views/templates/header.tpl.html'}
      }
    })
Abdullah Al Noman
la source
3

J'ai un état racine qui résout qc. Passer en $statetant que paramètre de résolution ne garantira pas la disponibilité pour $state.params. Mais en utilisant la $stateParamsvolonté.

var rootState = {
    name: 'root',
    url: '/:stubCompanyId',
    abstract: true,
    ...
};

// case 1:
rootState.resolve = {
    authInit: ['AuthenticationService', '$state', function (AuthenticationService, $state) {
        console.log('rootState.resolve', $state.params);
        return AuthenticationService.init($state.params);
    }]
};
// output:
// rootState.resolve Object {}

// case 2:
rootState.resolve = {
    authInit: ['AuthenticationService', '$stateParams', function (AuthenticationService, $stateParams) {
        console.log('rootState.resolve', $stateParams);
        return AuthenticationService.init($stateParams);
    }]
};
// output:
// rootState.resolve Object {stubCompanyId:...}

Utilisation de "angular": "~ 1.4.0", "angular-ui-router": "~ 0.2.15"

jchnxu
la source
2

Une observation intéressante que j'ai faite en passant des paramètres d'état précédents d'une route à une autre est que $ stateParams est hissé et écrase les paramètres d'état de la route précédente qui ont été passés avec les paramètres d'état actuels, mais l'utilisation de $state.params ne le fait pas.

Lors de l'utilisation $stateParams:

var stateParams        = {};
stateParams.nextParams = $stateParams; //{item_id:123}
stateParams.next       = $state.current.name;

$state.go('app.login', stateParams);
//$stateParams.nextParams on app.login is now:
//{next:'app.details', nextParams:{next:'app.details'}}

Lors de l'utilisation de $ state.params:

var stateParams        = {};
stateParams.nextParams = $state.params; //{item_id:123}
stateParams.next       = $state.current.name;

$state.go('app.login', stateParams);
//$stateParams.nextParams on app.login is now:
//{next:'app.details', nextParams:{item_id:123}}
Shaun E. Tobias
la source
1

Ici, dans cet article est clairement expliqué: Le $stateservice fournit un certain nombre de méthodes utiles pour manipuler l'état ainsi que des données pertinentes sur l'état actuel. Les paramètres de l'état actuel sont accessibles sur le $stateservice au niveau de la touche params. Le $stateParamsservice renvoie ce même objet. Par conséquent, le $stateParamsservice est strictement un service de commodité pour accéder rapidement à l'objet params sur le$state service.

En tant que tel, aucun contrôleur ne devrait jamais injecter à la fois le $stateservice et son service de commodité $stateParams. Si le $stateest injecté uniquement pour accéder aux paramètres actuels, le contrôleur doit être réécrit pour injecter à la $stateParamsplace.

pabloRN
la source