Bei Verwendung von onEnter zur Umleitung in einen Status tritt eine Endlosschleife auf, wenn der neue Status dem aktuellen Status untergeordnet ist.
Beispiel:
$stateProvider
.state 'inventory',
url: '/inventory'
templateUrl: 'views/inventory.html'
controller: 'InventoryCtrl'
onEnter: () ->
$state.go 'inventory.low'
.state 'inventory.low',
url: '/low'
templateUrl: 'views/inventory-table.html'
controller: 'LowInventoryCtrl'
Wann:
$state.go 'inventory.low'
Wird aufgerufen, wird der Zustand inventory
neu initialisiert, sodass er erneut aufgerufen wird = Endlosschleife.
Wenn der Umleitungsstatus jedoch lautet:
$state.go 'otherStateThatIsNotAChild'
Dieses Problem tritt nicht auf. Ich gehe davon aus, dass der übergeordnete Zustand neu initialisiert wird, aber warum?
.go
für einen untergeordneten Status aufgerufen wird?1) Warum wird der übergeordnete Zustand erneut initialisiert, wenn .go für eine .__ aufgerufen wird. Kindzustand
Während ein Übergang ausgeführt wird, führt jeder Übergang von $ state.go/transitionTo dazu, dass der Übergang derzeit in Bearbeitung ersetzt wird. Ein in-Process-Übergang, der ersetzt wird, wird sofort abgebrochen. Da Ihr ursprünglicher Übergang zu inventory
nicht abgeschlossen ist, wenn alle onEnters aller Zustände aufgerufen werden, wird der ursprüngliche Übergang abgebrochen und ein Übergang new zu inventory.low
wird aus dem zuvor aktiven Zustand gestartet.
Siehe ui-router src https://github.com/angular-ui/ui-router/blob/master/src/state.js#L897 ...
2) Wie würden Sie dann die Umleitung in einen untergeordneten Zustand durchführen?
Du könntest...
$state.go
in eine $timeout()
, damit der ursprüngliche Übergang vor der Umleitung abgeschlossen werden kann.Stellen Sie auf jeden Fall sicher, dass Ihre App so weitergeleitet werden soll. Wenn ein Benutzer direkt zu einem anderen untergeordneten Status des Inventars navigiert wurde (z. B. inventory.high
), wird die Weiterleitung trotzdem durchgeführt, wodurch er zu inventory.low
gezwungen wird. Dies wäre nicht der beabsichtigte Zweck.
Ich hatte das gleiche Problem. Die einfache Lösung, die ich gefunden habe, besteht darin, Statusänderungen zu hören und von dort zu Ihrem untergeordneten Status umzuleiten.
Es ist eine Art Hack, bei dem Routen standardmäßig in untergeordnete Status umgeleitet werden. Es ist nicht erforderlich,url: ''
oder $state.go()
auszuführen, sie funktionieren nicht richtig.
Also in config
Datei:
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState) {
if (toState.redirectTo) {
event.preventDefault();
$state.go(toState.redirectTo, toParams);
}
});
In state
Datei:
.state('home', {
url: '',
redirectTo: 'home.list'
});
Ich habe ein Beispiel für Gist gemacht: https://Gist.github.com/nikoloza/4ab3a94a3c6511bb1dac
Sie müssen einen Schritt zurücktreten und darüber nachdenken, was Sie erreichen wollen. Was ist der Sinn eines Zustands, wenn er nur zu einem untergeordneten Zustand umleitet?
In Bezug auf Ihre erste Frage werden Elternzustände immer aktiviert, wenn Sie zu einem untergeordneten Status gelangen. Dieses Verhalten ist äußerst hilfreich, wenn Sie Daten zwischen den Status teilen möchten. Ohne sie wäre verschachteltes Routing unmöglich (oder wäre nicht sinnvoll).
Bei der zweiten Frage habe ich an einigen großen eckigen Apps gearbeitet, die ich bisher nicht brauchte.
OK, glauben Sie es oder nicht, so sehr ich es hasse, es zu sagen, gerade jetzt bin ich auf ein Szenario gestoßen, in dem ich dies tun musste. Ich habe eine profile/userName
-Route (technisch sollte dies profile/userName/details
sein) und eine profile/userName/products
-Route. Ich wollte eine Master-Ansicht für beide Zustände haben, aber gleichzeitig wollte ich, dass die profile/userName
-Route eine saubere URL hat, wie: profile/mike62
, NICHT profile/mike62/details
. So endete ich damit:
.state('publicProfile', { url: '/profile/{username}'})//this is the base/Shell state
.state('publicProfile.details',{url:null})//I want this to be my de-facto state, with a clean URL, hence the null url
.state('publicProfile.products', {url:'/products/{exceptProductId:/?.*}'})
Am Ende ist es so, aber es gibt viele Möglichkeiten:
in meinem publicProfile
-Zustandscontroller (dies ist der Basiszustand):
$scope.state = $state;
$scope.$watch('state.current', function(v) {
if(v.name=='publicProfile') {//want to navigate to the 'preferred' state if not going to publicProfile.products
$state.go('publicProfile.details');
};
}, true);
Ja, es fühlt sich hackig an, aber jetzt weiß ich, dass es einige Edge-Fälle gibt, in denen wir dies tun möchten, obwohl wir unser Staatsdesign insgesamt überdenken könnten. Eine unansehnlichere Methode wäre, den aktuellen Status in einem $ timeout mit einer kleinen Verzögerung im Basisstatus zu überprüfen. Wenn wir uns nicht im publicProfile.products
-Status befinden, navigieren wir zu unserem bevorzugten/de-facto-Status von publicProfile.details
.
Es scheint, dass Sie versuchen, einen standardmäßigen untergeordneten Status festzulegen.
Dies ist eine häufig gestellte Frage zu ui-router: Gewusst wie: Einrichten eines standardmäßigen/untergeordneten Statusstatus
Tl; dr verwendet abstract states mit den Einstellungen abstract: true
im übergeordneten Status. Wenn Sie mehrere untergeordnete Status hinzufügen, wird standardmäßig der erste untergeordnete Status verwendet.
$stateProvider
.state('inventory', {
abstract: true,
url: '/inventory',
templateUrl: 'views/inventory.html',
controller: 'InventoryCtrl'
}).
.state('inventory.low', {
url: '/low',
templateUrl: 'views/inventory-table.html',
controller: 'LowInventoryCtrl'
});
Gemäß der Antwort von pdvorchik auf den bezogenen GitHub-Thread gibt es eine einfache Lösung für dieses Problem, die perfekt für mich funktionierte. Sie bestand darin, den Aufruf $state.go
in einen Aufruf von .finally()
einzuhüllen, um sicherzustellen, dass der erste Übergang abgeschlossen ist, bevor ein neuer gestartet wird.
onEnter: ['$state', function($state){
if ($state.transition) {
$state.transition.finally(function() {
$state.go('home.my.other.state', {})
});
}
}]
Nach der Erklärung von @Chris T scheint es die sauberste Lösung zu sein, auf das $stateChangeSuccess
-Ereignis zu achten:
redirects =
inventory: 'inventory.low'
$rootScope.$on '$stateChangeSuccess', (e, toState) ->
redirect = redirects[toState.name]
$state.go redirect if redirect
Wo Weiterleitungen eventuelle Routenumleitungen enthalten. Danke euch allen!
Machen Sie den niedrigen Lagerbestand nicht zu einem untergeordneten Status.
$stateProvider
.state 'inventory',
url: '/inventory'
templateUrl: 'views/inventory.html'
controller: 'InventoryCtrl'
onEnter: () ->
$state.go 'lowinventory'
.state 'lowinventory',
url: '/inventory/low'
templateUrl: 'views/inventory-table.html'
controller: 'LowInventoryCtrl'