Avec ui-router
, il est possible d'injecter soit $state
ou $stateParams
dans un contrôleur pour accéder aux paramètres de l'URL. Cependant, l'accès aux paramètres via $stateParams
expose uniquement les paramètres appartenant à l'état géré par le contrôleur qui y accède, ainsi que ses états parents, tandis que $state.params
possède tous les paramètres, y compris ceux de tous les états enfants.
Étant donné le code suivant, si nous chargeons directement l'URL http://path/1/paramA/paramB
, voici comment cela se passe lors du chargement des contrôleurs:
$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 le moment et la raison pour lesquels vous devriez utiliser ou éviter de les utiliser?
La documentation réitère vos conclusions ici: https://github.com/angular-ui/ui-router/wiki/URL-Routing#stateparams-service
Si ma mémoire est bonne, $stateParams
a été introduit plus tard que l'original $state.params
, et semble être un simple injecteur auxiliaire pour éviter d'écrire en continu $state.params
.
Je doute qu'il existe 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 à propos de l'état lui-même, utilisez $state
.
Une autre raison d'utiliser $state.params
est pour un état non basé sur une URL, ce qui (selon moi) est terriblement sous-documenté et très puissant.
Je viens de découvrir cela en cherchant sur Google comment passer d'un état à un autre sans avoir à l'exposer dans l'URL et répondu à une question ailleurs sur SO.
Fondamentalement, cela permet ce genre de syntaxe:
<a ui-sref="toState(thingy)" class="list-group-item" ng-repeat="thingy in thingies">{{ thingy.referer }}</a>
EDIT: Cette réponse est correcte pour la version 0.2.10
. Comme @Alexander Vasilyev l'a souligné, cela ne fonctionne pas dans la version 0.2.14
.
Une autre raison d'utiliser $state.params
est 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
}
Il y a beaucoup de différences entre ces deux. Mais en travaillant, j’ai constaté que mieux utiliser $state.params
. Lorsque vous utilisez de plus en plus de paramètres, la maintenance dans $stateParams
peut être compliquée. où si nous utilisons plusieurs paramètres qui ne sont pas des URL, le paramètre $state
est 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'}
}
})
J'ai un état racine qui résout qc. Le fait de passer $state
en tant que paramètre de résolution ne garantit pas la disponibilité de $state.params
. Mais en utilisant $stateParams
sera.
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"
Une observation intéressante que j'ai faite lors du passage des paramètres d'état précédents d'une route à une autre est que $ stateParams est levé et écrase les paramètres d'état de la route précédente qui ont été transmis avec les paramètres d'état actuels, mais pas $state.param
s.
Lorsque vous utilisez $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'}}
Lorsque vous utilisez $ 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}}
Ici dans cet article est clairement expliqué: Le service $state
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 d'état en cours sont accessibles sur le service $state
à la touche params. Le service $stateParams
renvoie ce même objet. Par conséquent, le service $stateParams
est strictement un service de commodité permettant d’accéder rapidement à l’objet params du service $state
.
En tant que tel, aucun contrôleur ne doit jamais injecter à la fois le service $state
et son service de proximité, $stateParams
. Si le $state
est injecté uniquement pour accéder aux paramètres actuels, le contrôleur doit être réécrit pour injecter $stateParams
à la place.