Czy istnieje sposób, aby uzyskać poprzedni stan obecnego stanu?
Na przykład chciałbym wiedzieć, jaki był poprzedni stan przed obecnym stanem B (gdzie poprzedni stan byłby stanem A).
Nie mogę go znaleźć na stronach doc github ui-routera.
Czy istnieje sposób, aby uzyskać poprzedni stan obecnego stanu?
Na przykład chciałbym wiedzieć, jaki był poprzedni stan przed obecnym stanem B (gdzie poprzedni stan byłby stanem A).
Nie mogę go znaleźć na stronach doc github ui-routera.
Odpowiedzi:
ui-router nie śledzi poprzedniego stanu po przejściu, ale zdarzenie $stateChangeSuccess
jest emitowane w $rootScope
momencie zmiany stanu.
Powinieneś być w stanie złapać poprzedni stan z tego wydarzenia ( from
jest to stan, z którego wychodzisz):
$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
//assign the "from" parameter to something
});
Używam rozwiązania, aby zapisać dane bieżącego stanu przed przejściem do nowego stanu:
angular.module('MyModule')
.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('mystate', {
templateUrl: 'mytemplate.html',
controller: ["PreviousState", function (PreviousState) {
if (PreviousState.Name == "mystate") {
// ...
}
}],
resolve: {
PreviousState: ["$state", function ($state) {
var currentStateData = {
Name: $state.current.name,
Params: $state.params,
URL: $state.href($state.current.name, $state.params)
};
return currentStateData;
}]
}
});
}]);
$stateChangeSuccess
$stateChangeSuccess
działa, robi to na poziomie globalnym, co nie jest potrzebne przez większość czasu.
$state.current
jest obiekt: {name: "", url: "^", views: null, abstract: true}
.
Ze względu na czytelność umieszczę tutaj moje rozwiązanie (oparte na anwser stu.salsbury).
Dodaj ten kod do abstrakcyjnego szablonu aplikacji, aby działał na każdej stronie.
$rootScope.previousState;
$rootScope.currentState;
$rootScope.$on('$stateChangeSuccess', function(ev, to, toParams, from, fromParams) {
$rootScope.previousState = from.name;
$rootScope.currentState = to.name;
console.log('Previous state:'+$rootScope.previousState)
console.log('Current state:'+$rootScope.currentState)
});
Śledzi zmiany w rootScope. Jest całkiem poręczny.
W poniższym przykładzie utworzyłem decorator
(działa tylko raz na aplikację w fazie konfiguracji) i dodaje dodatkową właściwość do $state
usługi, więc to podejście nie dodaje zmiennych globalnych$rootscope
do innych usług i nie wymaga dodawania żadnych dodatkowych zależności do innych usług niż $state
.
W moim przykładzie musiałem przekierować użytkownika na stronę indeksową, gdy był już zalogowany i kiedy nie miał przekierowywać go na poprzednią „chronioną” stronę po zalogowaniu.
Nieznane tylko usługi (dla ciebie), które używam są authenticationFactory
i appSettings
:
authenticationFactory
po prostu zarządza loginem użytkownika. W tym przypadku używam tylko metody identyfikacji, czy użytkownik jest zalogowany, czy nie.appSettings
są stałymi tylko po to, aby nie używać wszędzie łańcuchów. appSettings.states.login
i appSettings.states.register
zawierać nazwę stanu dla logowania i adresu URL rejestru.Następnie w dowolnym controller
/ service
etc musisz wstrzyknąć $state
usługę i możesz uzyskać dostęp do bieżącego i poprzedniego adresu URL w następujący sposób:
$state.current.name
$state.previous.route.name
Z konsoli Chrome:
var injector = angular.element(document.body).injector();
var $state = injector.get("$state");
$state.current.name;
$state.previous.route.name;
Realizacja:
(Używam angular-ui-router v0.2.17
i angularjs v1.4.9
)
(function(angular) {
"use strict";
function $stateDecorator($delegate, $injector, $rootScope, appSettings) {
function decorated$State() {
var $state = $delegate;
$state.previous = undefined;
$rootScope.$on("$stateChangeSuccess", function (ev, to, toParams, from, fromParams) {
$state.previous = { route: from, routeParams: fromParams }
});
$rootScope.$on("$stateChangeStart", function (event, toState/*, toParams, fromState, fromParams*/) {
var authenticationFactory = $injector.get("authenticationFactory");
if ((toState.name === appSettings.states.login || toState.name === appSettings.states.register) && authenticationFactory.isUserLoggedIn()) {
event.preventDefault();
$state.go(appSettings.states.index);
}
});
return $state;
}
return decorated$State();
}
$stateDecorator.$inject = ["$delegate", "$injector", "$rootScope", "appSettings"];
angular
.module("app.core")
.decorator("$state", $stateDecorator);
})(angular);
Dodaj nową właściwość o nazwie {previous} do $ state na $ stateChangeStart
$rootScope.$on( '$stateChangeStart', ( event, to, toParams, from, fromParams ) => {
// Add {fromParams} to {from}
from.params = fromParams;
// Assign {from} to {previous} in $state
$state.previous = from;
...
}
Teraz gdziekolwiek potrzebujesz, możesz użyć $ state, będziesz mieć poprzednią dostępną
previous:Object
name:"route name"
params:Object
someParam:"someValue"
resolve:Object
template:"route template"
url:"/route path/:someParam"
I używaj go w ten sposób:
$state.go( $state.previous.name, $state.previous.params );
Utknąłem z tym samym problemem i znajduję najłatwiejszy sposób, aby to zrobić ...
//Html
<button type="button" onclick="history.back()">Back</button>
LUB
//Html
<button type="button" ng-click="goBack()">Back</button>
//JS
$scope.goBack = function() {
window.history.back();
};
(Jeśli chcesz, aby było bardziej testowalne, wstrzyknij usługę $ window do kontrolera i użyj $ window.history.back ()).
Stosuję podobne podejście do tego, co robi Endy Tjahjono.
To, co robię, to zapisywanie wartości bieżącego stanu przed dokonaniem przejścia. Zobaczmy na przykładzie; wyobraź sobie to wewnątrz funkcji wykonywanej po kliknięciu na cokolwiek wyzwala przejście:
$state.go( 'state-whatever', { previousState : { name : $state.current.name } }, {} );
Kluczem jest tutaj obiekt params (mapa parametrów, które zostaną przesłane do stanu) -> { previousState : { name : $state.current.name } }
Uwaga: zwróć uwagę, że ja tylko „zapisuję” atrybut name obiektu $ state, ponieważ jest to jedyna rzecz, której potrzebuję do zapisania stanu. Ale moglibyśmy mieć cały obiekt stanu.
Następnie określ „cokolwiek” zostało zdefiniowane w ten sposób:
.state( 'user-edit', {
url : 'whatever'
templateUrl : 'whatever',
controller: 'whateverController as whateverController',
params : {
previousState: null,
}
});
Tutaj kluczowym punktem jest obiekt params.
params : {
previousState: null,
}
Następnie w tym stanie możemy uzyskać poprzedni stan w następujący sposób:
$state.params.previousState.name
Oto naprawdę eleganckie rozwiązanie autorstwa Chrisa Thielena ui-router-extras: $ previousState
var previous = $previousState.get(); //Gets a reference to the previous state.
previous
jest obiektem, który wygląda następująco: { state: fromState, params: fromParams }
gdzie fromState to poprzedni stan, a fromParams to poprzednie parametry stanu.
Ok, wiem, że spóźniłem się na imprezę tutaj, ale jestem nowy w Angular. Próbuję dopasować to do przewodnika po stylu Johna Papy . Chciałem, aby to było wielokrotnego użytku, więc utworzyłem w bloku. Oto co wymyśliłem:
previousStateProvider
(function () {
'use strict';
angular.module('blocks.previousState')
.provider('previousState', previousStateProvider);
previousStateProvider.$inject = ['$rootScopeProvider'];
function previousStateProvider($rootScopeProvider) {
this.$get = PreviousState;
PreviousState.$inject = ['$rootScope'];
/* @ngInject */
function PreviousState($rootScope) {
$rootScope.previousParms;
$rootScope.previousState;
$rootScope.currentState;
$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
$rootScope.previousParms = fromParams;
$rootScope.previousState = from.name;
$rootScope.currentState = to.name;
});
}
}
})();
core.module
(function () {
'use strict';
angular.module('myApp.Core', [
// Angular modules
'ngMessages',
'ngResource',
// Custom modules
'blocks.previousState',
'blocks.router'
// 3rd Party Modules
]);
})();
core.config
(function () {
'use strict';
var core = angular.module('myApp.Core');
core.run(appRun);
function appRun(previousState) {
// do nothing. just instantiating the state handler
}
})();
Każda krytyka dotycząca tego kodu może mi tylko pomóc, więc daj mi znać, gdzie mogę go ulepszyć.
Jeśli potrzebujesz tylko tej funkcji i chcesz jej używać w więcej niż jednym kontrolerze, jest to prosta usługa śledzenia historii tras:
(function () {
'use strict';
angular
.module('core')
.factory('RouterTracker', RouterTracker);
function RouterTracker($rootScope) {
var routeHistory = [];
var service = {
getRouteHistory: getRouteHistory
};
$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
routeHistory.push({route: from, routeParams: fromParams});
});
function getRouteHistory() {
return routeHistory;
}
return service;
}
})();
gdzie „rdzeń” w .module („rdzeń”) byłby nazwą Twojej aplikacji / modułu. Wymagaj usługi jako zależności od kontrolera, a następnie w kontrolerze możesz wykonać:$scope.routeHistory = RouterTracker.getRouteHistory()
Śledzę poprzednie stany w $ rootScope , więc w razie potrzeby po prostu wywołam poniższą linię kodu.
$state.go($rootScope.previousState);
W App.js :
$rootScope.$on('$stateChangeSuccess', function(event, to, toParams, from, fromParams) {
$rootScope.previousState = from.name;
});
W przypadku UI-Router (> = 1.0) zdarzenia StateChange zostały wycofane. Aby uzyskać pełny przewodnik po migracji, kliknij tutaj
Aby uzyskać poprzedni stan bieżącego stanu w UI-Router 1.0+:
app.run(function ($transitions) {
$transitions.onSuccess({}, function (trans) {
// previous state and paramaters
var previousState = trans.from().name;
var previousStateParameters = trans.params('from');
});
});
Naprawdę prostym rozwiązaniem jest po prostu zmodyfikowanie ciągu $ state.current.name i wycięcie wszystkiego, łącznie z ostatnim znakiem „i po nim”. - otrzymasz nazwę państwa macierzystego. To nie działa, jeśli dużo przeskakujesz między stanami, ponieważ po prostu analizuje bieżącą ścieżkę. Ale jeśli twoje stany odpowiadają temu, gdzie faktycznie jesteś, to działa.
var previousState = $state.current.name.substring(0, $state.current.name.lastIndexOf('.'))
$state.go(previousState)
$state.go('^')
osiągnie to
Możesz zwrócić stan w ten sposób:
$state.go($state.$current.parent.self.name, $state.params);
Przykład:
(function() {
'use strict'
angular.module('app')
.run(Run);
/* @ngInject */
function Run($rootScope, $state) {
$rootScope.back = function() {
$state.go($state.$current.parent.self.name, $state.params);
};
};
})();