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


116

З ui-routerцим можна ввести $stateабо $stateParamsв контролер, щоб отримати доступ до параметрів у URL-адресі. Однак доступ до параметрів здійснюється $stateParamsлише через параметри, що належать до стану, керованого контролером, який здійснює доступ до нього, та його батьківських станів, при цьому $state.paramsмає всі параметри, в тому числі в будь-яких дочірніх станах.

З огляду на наступний код, якщо ми безпосередньо завантажуємо URL-адресу http://path/1/paramA/paramB, так це відбувається, коли контролери завантажують:

$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
}

Питання в тому, чому різниця? І чи є вказівки щодо найкращих практик щодо того, коли і навіщо слід використовувати, чи уникати використання будь-якого з них?


Таке чудово ілюстроване запитання - дякую, що сказали мені навіть те, що я намагався задати!
Пітер Ніксей

Відповіді:


65

Документація повторює ваші висновки тут: https://github.com/angular-ui/ui-router/wiki/URL-Routing#stateparams-service

Якщо моя пам'ять слугує, $stateParamsбула введена пізніше оригіналу $state.paramsі, здається, є простим помічником-інжектором, щоб уникнути постійного написання $state.params.

Я сумніваюся, що є якісь рекомендації щодо найкращої практики, але контекст для мене виграє. Якщо ви просто хочете отримати доступ до парам, що надійшли в URL, тоді скористайтеся $stateParams. Якщо ви хочете дізнатись про щось складніше про саму державу, використовуйте $state.


1
Я знайшов себе $state.paramsв користуванні ACtrl, тому що хотів перевірити, чи yetAnotherParamвстановлено. Так що якщо це не так, я можу щось зробити. Я не вникаю в подробиці цього чогось, оскільки це може дати певне власне питання. Однак я вважаю, що я можу робити злом , перевіряючи параметр, який вводиться дочірнім станом і не розпізнається поточним станом $stateParams. З того часу я знайшов альтернативний підхід.
Меротт

3
Власне, різниця між цими двома є не лише питанням контексту. $ stateParams фіксує параметри, засновані на URL, для яких $ state вважає, що застосовується до цього стану, навіть якщо його дочірній стан містить більше парам . $ state.params, схоже, охоплює всі параметри, що базуються на URL-адресі, а не на URL-адресі поточного стану, в якому ви перебуваєте. Якщо ви перебуваєте в стані parent.child, то $stateParamsв parentControllerоцінюватимете параметри, що базуються на URL parent, але не ті parent.child. Дивіться це питання .
Amy.js

1
З іншого боку, $ stateParams може зберігати власні об'єкти, типи тощо, тоді як $ state.params "перетворює власні об'єкти у звичайні об'єкти".
Amy.js

2
$stateParamsпрацює в $state.params
рішучій мові

1
Я виявив, що область може $ watch $ state.params, але не $ stateParams. Я поняття не маю, чому.
weltschmerz

19

Ще одна причина використання $state.params- це стан, що не базується на URL, який (на мій погляд) є надзвичайно недокументованим та дуже потужним.

Я щойно виявив це, гуглюючи про те, як передати стан, не виставляючи його в URL-адресі, і відповів на запитання в іншому місці SO.

В основному, це дозволяє такий синтаксис:

<a ui-sref="toState(thingy)" class="list-group-item" ng-repeat="thingy in thingies">{{ thingy.referer }}</a>

Привіт bbrown, я якось не можу змусити його працювати, у вас є робочий приклад?
storm_buster

14

EDIT: Ця відповідь правильна для версії 0.2.10. Як зазначив @Alexander Васильєв, він не працює у версії 0.2.14.

Ще одна причина використання $state.params- це коли потрібно витягти такі параметри запиту:

$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
}

2
Більше не застосовується. Дивіться Plunker: plnkr.co/edit/r2JhV4PcYpKJdBCwHIWS?p=preview
Олександр Васильєв

4

Існує багато відмінностей між цими двома. Але працюючи практично, я виявив, що використовую $state.paramsкраще. Якщо ви використовуєте все більше та більше параметрів, це може бути незрозумілим для підтримки $stateParams. де, якщо ми використовуємо кілька парам, які не є URL-парам $state, дуже корисно

 .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'}
      }
    })

3

У мене є кореневий стан, який вирішує sth. Проходження $stateв якості параметра вирішення не гарантує доступність для $state.params. Але використовуючи $stateParamsволю.

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:...}

Використання "angular": "~ 1.4.0", "angular-ui-router": "~ 0.2.15"


2

Цікаве зауваження, яке я зробив під час передачі попередніх парам станцій з одного маршруту на інший, - це те, що $ stateParams піднімається та перезаписує парами стану попереднього маршруту, передані разом із поточними парамами стану, але використання $state.params не виконує.

При використанні $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'}}

При використанні $ 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}}

1

Тут у цій статті чітко пояснено: $stateСервіс надає ряд корисних методів для маніпулювання станом, а також відповідні дані про поточний стан. Параметри поточного стану доступні в $stateсервісі за допомогою клавіші params. $stateParamsСлужба повертає це той же самий об'єкт. Отже, $stateParamsсервіс є суворо зручним сервісом для швидкого доступу до об’єкта парам в $stateслужбі.

Таким чином , ні один контролер ніколи не повинен вводити як $stateсервіс і його обслуговування зручності $stateParams. Якщо $stateвводиться просто для доступу до поточних параметрів, контролер слід переписати для введення $stateParamsзамість цього.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.