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


116

Con ui-router, è possibile iniettare $stateo $stateParamsin un controller per ottenere l'accesso ai parametri nell'URL. Tuttavia, l'accesso ai parametri tramite $stateParamsespone solo i parametri appartenenti allo stato gestito dal controllore che vi accede e ai suoi stati padre, pur $state.paramsavendo tutti i parametri, inclusi quelli in eventuali stati figli.

Dato il seguente codice, se carichiamo direttamente l'URL http://path/1/paramA/paramB, ecco come va quando vengono caricati i controller:

$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 domanda è: perché la differenza? E ci sono linee guida sulle migliori pratiche su quando e perché dovresti usarle o evitare di usarle?


Una domanda così illustrata in modo eccellente - grazie per avermi detto anche quello che stavo cercando di chiedere!
Peter Nixey

Risposte:


65

La documentazione ribadisce le tue scoperte qui: https://github.com/angular-ui/ui-router/wiki/URL-Routing#stateparams-service

Se la mia memoria serve, è $stateParamsstata introdotta più tardi dell'originale $state.params, e sembra essere un semplice aiutante iniettore per evitare di scrivere continuamente $state.params.

Dubito che ci siano linee guida per le migliori pratiche, ma il contesto vince per me. Se vuoi semplicemente accedere ai parametri ricevuti nell'URL, usa $stateParams. Se vuoi sapere qualcosa di più complesso sullo stato stesso, usa $state.


1
Mi sono ritrovato a usare $state.paramsin ACtrl, perché volevo controllare se yetAnotherParamè impostato. Quindi, se non lo è, posso fare qualcosa. Non entrerò nei dettagli di quel qualcosa in quanto potrebbe giustificare una questione a sé stante. Tuttavia, sento che potrei fare un hack controllando un parametro introdotto da uno stato figlio e non riconosciuto dallo stato corrente $stateParams. Da allora ho trovato un approccio alternativo.
Merott

3
In realtà, la differenza tra i due è più di una semplice questione di contesto. $ stateParams acquisisce i parametri basati su URL che $ state considera applicabili a quello stato, anche se il suo stato figlio contiene più parametri . $ state.params sembra catturare tutti i parametri url + non basati su URL dello stato corrente in cui ci si trova. Se ci si trova nello stato parent.child, $stateParamsin parentControllervaluterà i parametri basati su URL di parent, ma non quelli di parent.child. Vedi questo problema .
Amy.js

1
D'altra parte, $ stateParams può conservare oggetti personalizzati, tipi, ecc. Mentre $ state.params "converte oggetti personalizzati in oggetti semplici".
Amy.js

2
$stateParamsfunziona in risoluzione, mentre $state.paramsnon è corretto (non mostra i parametri per lo stato che non è stato ancora risolto)
karaxuna

1
Ho scoperto che l'ambito può $ guardare $ state.params, ma non $ stateParams. Non ho idea del perché.
weltschmerz

19

Un altro motivo per utilizzare $state.paramsè per lo stato non basato su URL, che (a mio avviso) è purtroppo poco documentato e molto potente.

L'ho appena scoperto mentre cercavo su Google come passare lo stato senza doverlo esporre nell'URL e ho risposto a una domanda altrove su SO.

Fondamentalmente, consente questo tipo di sintassi:

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

Ciao bbrown, in qualche modo non riesco a farlo funzionare, hai un esempio funzionante?
storm_buster

14

EDIT: questa risposta è corretta per la versione 0.2.10. Come ha sottolineato @Alexander Vasilyev, non funziona nella versione 0.2.14.

Un altro motivo per utilizzarlo $state.paramsè quando è necessario estrarre parametri di query in questo modo:

$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
Non più applicabile. Vedi Plunker: plnkr.co/edit/r2JhV4PcYpKJdBCwHIWS?p=preview
Alexander Vasilyev

4

Ci sono molte differenze tra questi due. Ma mentre lavoravo praticamente ho scoperto che usando $state.paramsmeglio. Quando si utilizzano sempre più parametri, potrebbe creare confusione mantenerli $stateParams. dove se usiamo più parametri che non sono parametri URL $stateè molto 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'}
      }
    })

3

Ho uno stato radice che risolve qc. Il passaggio $statecome parametro di risoluzione non garantisce la disponibilità per $state.params. Ma usando $stateParamswill.

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

Utilizzo di "angular": "~ 1.4.0", "angular-ui-router": "~ 0.2.15"


2

Un'osservazione interessante che ho fatto durante il passaggio dei parametri di stato precedenti da una rotta a un'altra è che $ stateParams viene sollevato e sovrascrive i parametri di stato della rotta precedente che sono stati passati con i parametri di stato correnti, ma l'uso di $state.params non lo fa.

Quando si utilizza $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'}}

Quando si utilizza $ 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

In questo articolo è spiegato chiaramente: Il $stateservizio fornisce una serie di metodi utili per manipolare lo stato, nonché dati pertinenti sullo stato corrente. I parametri dello stato corrente sono accessibili sul $stateservizio alla chiave params. Il $stateParamsservizio restituisce questo stesso oggetto. Quindi, il $stateParamsservizio è strettamente un servizio di convenienza per accedere rapidamente all'oggetto params nel file$state servizio.

In quanto tale, nessun controller dovrebbe mai iniettare sia il $stateservizio e il suo servizio di convenienza, $stateParams. Se $stateviene iniettato solo per accedere ai parametri correnti, il controller dovrebbe essere riscritto per iniettare $stateParams.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.