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

116

Za pomocą ui-routermożna wstrzyknąć kontroler $statelub $stateParamsdo kontrolera, aby uzyskać dostęp do parametrów w adresie URL. Jednak dostęp do parametrów za pośrednictwem $stateParamsujawnia tylko parametry należące do stanu zarządzanego przez kontroler, który uzyskuje do niego dostęp, oraz jego stany nadrzędne, podczas gdy $state.paramsma wszystkie parametry, w tym te w stanach potomnych.

Biorąc pod uwagę następujący kod, jeśli bezpośrednio załadujemy adres URL http://path/1/paramA/paramB, wygląda to tak, gdy ładują się kontrolery:

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

Pytanie brzmi, skąd ta różnica? Czy istnieją wskazówki dotyczące najlepszych praktyk dotyczące tego, kiedy i dlaczego należy ich używać lub unikać?

Merott
źródło
Takie świetnie ilustrowane pytanie - dziękuję za powiedzenie mi nawet tego, o co próbowałem zapytać!
Peter Nixey,

Odpowiedzi:

65

Dokumentacja powtarza twoje ustalenia tutaj: https://github.com/angular-ui/ui-router/wiki/URL-Routing#stateparams-service

Jeśli moja pamięć służy, $stateParamszostała wprowadzona później niż oryginał $state.paramsi wydaje się być prostym wtryskiwaczem pomocniczym, aby uniknąć ciągłego pisania $state.params.

Wątpię, czy istnieją jakieś wskazówki dotyczące najlepszych praktyk, ale kontekst wygrywa dla mnie. Jeśli po prostu chcesz uzyskać dostęp do parametrów otrzymanych w adresie URL, użyj $stateParams. Jeśli chcesz dowiedzieć się czegoś bardziej złożonego o samym stanie, użyj $state.

Matt Way
źródło
1
Znalazłem się $state.paramsw ACtrlgrze, bo chciałem sprawdzić czy yetAnotherParamjest ustawione. Więc jeśli tak nie jest, mogę coś zrobić. Nie wchodzę w szczegóły tego czegoś, ponieważ mogłoby to uzasadniać pytanie samo w sobie. Jednak wydaje mi się, że mogę robić hackowanie , sprawdzając parametr, który jest wprowadzany przez stan potomny i nie jest rozpoznawany przez bieżący stan do $stateParams. Od tego czasu znalazłem alternatywne podejście.
Merott,
3
W rzeczywistości różnica między nimi to coś więcej niż tylko kwestia kontekstu. $ stateParams przechwytuje parametry oparte na adresach URL, które $ state uważa za mające zastosowanie do tego stanu, nawet jeśli jego stan podrzędny zawiera więcej parametrów . Wygląda na to, że $ state.params przechwytuje wszystkie parametry bieżącego stanu , w którym się znajdujesz parent.child, i nie oparte na adresach URL . Jeśli jesteś w stanie , program $stateParamsin parentControlleroceni parametry oparte na adresach URL parent, ale nie te z parent.child. Zobacz ten numer .
Amy.js
1
Z drugiej strony $ stateParams może zachowywać niestandardowe obiekty, typy itp., Podczas gdy $ state.params „konwertuje niestandardowe obiekty na zwykłe obiekty”.
Amy.js
2
$stateParamsdziała w rozwiązaniu, podczas gdy $state.paramsjest niepoprawne (nie pokazuje parametrów stanu, który nie został jeszcze rozwiązany)
karaxuna
1
Odkryłem, że zakres może oglądać $ state.params, ale nie $ stateParams. Nie mam pojęcia dlaczego.
weltschmerz
19

Innym powodem do użycia $state.paramsjest stan nie oparty na adresie URL, który (moim zdaniem) jest żałośnie nieudokumentowany i bardzo potężny.

Właśnie odkryłem to podczas wyszukiwania w Google, jak przekazać stan bez konieczności ujawniania go w adresie URL i odpowiedziałem na pytanie w innym miejscu na SO.

Zasadniczo pozwala na ten rodzaj składni:

<a ui-sref="toState(thingy)" class="list-group-item" ng-repeat="thingy in thingies">{{ thingy.referer }}</a>
brązowy
źródło
Cześć brown, jakoś nie mogę sprawić, żeby to zadziałało, czy masz działający przykład?
storm_buster
14

EDYCJA: Ta odpowiedź jest poprawna dla wersji 0.2.10. Jak zauważył @Alexander Vasilyev, nie działa w wersji 0.2.14.

Innym powodem do użycia $state.paramsjest wyodrębnienie parametrów zapytania w następujący sposób:

$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
źródło
2
Już nie dotyczy. Zobacz Plunker: plnkr.co/edit/r2JhV4PcYpKJdBCwHIWS?p=preview
Alexander Wasiljew
4

Istnieje wiele różnic między tymi dwoma. Ale pracując praktycznie, przekonałem się, że $state.paramslepiej. Gdy używasz coraz większej liczby parametrów, może to być kłopotliwe w utrzymaniu $stateParams. gdzie jeśli używamy wielu parametrów, które nie są parametrami adresu URL, $statejest to bardzo przydatne

 .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
źródło
3

Mam stan root, który rozwiązuje coś. Przekazanie $statejako parametru rozpoznawania nie gwarantuje dostępności dla $state.params. Ale używając $stateParamswoli.

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

Korzystanie z „kątowego”: „~ 1,4.0”, „angular-ui-router”: „~ 0,2,15”

jchnxu
źródło
2

Ciekawą obserwacją, jaką poczyniłem podczas przekazywania poprzednich parametrów stanu z jednej trasy do drugiej, jest to, że $ stateParams zostaje podniesione i nadpisuje parametry stanu poprzedniej trasy, które zostały przekazane z bieżącymi parametrami stanu, ale użycie $state.params nie.

Podczas używania $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'}}

Używając $ 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
źródło
1

Tutaj w tym artykule jest wyraźnie wyjaśnione: the $stateserwis oferuje szereg przydatnych metod manipulowania stan, a także istotne dane na temat aktualnego stanu. Aktualne parametry stanu są dostępne w $stateusłudze pod kluczem params. $stateParamsUsługa zwraca ten bardzo sam obiekt. W związku z tym $stateParamsusługa jest usługą ściśle wygodną, ​​polegającą na szybkim dostępie do obiektu parametrów w $stateusłudze.

W związku z tym żaden kontroler nie powinien nigdy wstrzykiwać zarówno $stateusługi, jak i jej wygodnej usługi $stateParams. Jeśli $statejest wstrzykiwany tylko po to, aby uzyskać dostęp do bieżących parametrów, kontroler powinien zostać przepisany, aby $stateParamszamiast tego wstrzykiwać .

pabloRN
źródło