Чи є спосіб отримати попередній стан поточного стану?
Наприклад, я хотів би знати, яким був попередній стан до поточного стану B (де попередній стан був би станом A).
Я не в змозі знайти його на сторінках doc uc-router github.
Чи є спосіб отримати попередній стан поточного стану?
Наприклад, я хотів би знати, яким був попередній стан до поточного стану B (де попередній стан був би станом A).
Я не в змозі знайти його на сторінках doc uc-router github.
Відповіді:
ui-роутер не відстежує попередній стан, коли він переходить, але подія $stateChangeSuccess
транслюється на $rootScope
момент зміни стану.
Ви повинні мати можливість спіймати попередній стан цієї події ( from
це стан, який ви залишаєте):
$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
//assign the "from" parameter to something
});
Я використовую рішення для збереження даних поточного стану перед переходом у новий стан:
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
працює, але це робиться на глобальному рівні, що не дуже потрібне більшість часу.
$state.current
є об'єктом: {name: "", url: "^", views: null, abstract: true}
.
Заради читабельності я розміщу тут своє рішення (засноване на прихильнику сту.сальсбері).
Додайте цей код до абстрактного шаблону програми, щоб він працював на кожній сторінці.
$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)
});
Слідкує за змінами в rootScope. Це досить зручно.
У наступному прикладі я створив decorator
(працює лише один раз на додаток на етапі конфігурації) і додає додаткову властивість до $state
сервісу, тому цей підхід не додає глобальних змінних до $rootscope
і не вимагає додавання додаткової залежності до інших служб, ніж $state
.
У моєму прикладі мені потрібно було перенаправити користувача на індексну сторінку, коли він уже був увійшов і коли він не мав перенаправляти його на попередню "захищену" сторінку після входу.
Єдині невідомі сервіси (для вас), якими я користуюся, є authenticationFactory
іappSettings
:
authenticationFactory
просто керує логіном користувача. У цьому випадку я використовую лише метод, щоб визначити, чи користувач увійшов чи ні.appSettings
є константами просто для того, щоб не використовувати рядки всюди. appSettings.states.login
і appSettings.states.register
містять ім'я штату для реєстрації та реєстрації.Тоді в будь-який controller
/ service
etc вам потрібно ввести $state
послугу, і ви можете отримати доступ до поточної та попередньої URL-адреси на зразок цієї:
$state.current.name
$state.previous.route.name
З консолі Chrome:
var injector = angular.element(document.body).injector();
var $state = injector.get("$state");
$state.current.name;
$state.previous.route.name;
Впровадження:
(Я використовую angular-ui-router v0.2.17
і 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);
Додайте нову властивість під назвою {попередній} до $ state у $ 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;
...
}
Тепер де завгодно, ви можете використовувати $ state, у вас буде попереднє доступне
previous:Object
name:"route name"
params:Object
someParam:"someValue"
resolve:Object
template:"route template"
url:"/route path/:someParam"
І використовуйте його так:
$state.go( $state.previous.name, $state.previous.params );
Я застряг у тому ж питанні і знаходжу найпростіший спосіб зробити це ...
//Html
<button type="button" onclick="history.back()">Back</button>
АБО
//Html
<button type="button" ng-click="goBack()">Back</button>
//JS
$scope.goBack = function() {
window.history.back();
};
(Якщо ви хочете, щоб він був більш перевіреним, введіть службу $ window у свій контролер і використовуйте $ window.history.back ()).
Я використовую подібний підхід до того, що робить Енді Тяджоно.
Що я роблю, це зберегти значення поточного стану перед тим, як зробити перехід. Подивимось на прикладі; уявіть це всередині функції, що виконується при натисканні на те, що викликає перехід:
$state.go( 'state-whatever', { previousState : { name : $state.current.name } }, {} );
Ключовим тут є об'єкт params (карта параметрів, які будуть надіслані державі) -> { previousState : { name : $state.current.name } }
Примітка: зауважте, що я лише "зберігаю" атрибут імені об'єкта $ state, тому що це єдине, що мені потрібно для збереження стану. Але ми могли мати весь державний об’єкт.
Потім, зазначте "що завгодно", щоб було визначено так:
.state( 'user-edit', {
url : 'whatever'
templateUrl : 'whatever',
controller: 'whateverController as whateverController',
params : {
previousState: null,
}
});
Тут ключовим моментом є об’єкт парам.
params : {
previousState: null,
}
Тоді, всередині цього стану, ми можемо отримати попередній стан таким:
$state.params.previousState.name
Ось справді елегантне рішення від Chris Thielen ui-router-extras: $ previousState
var previous = $previousState.get(); //Gets a reference to the previous state.
previous
це об'єкт, який виглядає так: { state: fromState, params: fromParams }
де fromState - попередній стан, а зParams - попередні параметри стану.
Гаразд, я знаю, що я спізнююсь на вечірку тут, але я новачок. Я намагаюся зробити це вписаним у посібник зі стилю Джона Папи тут. Я хотів зробити це для багаторазового використання, тому створив у блоці. Ось що я придумав:
попереднійStateProvider
(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
}
})();
Будь-яка критика щодо цього коду допоможе лише мені, тому, будь ласка, дайте мені знати, де я можу вдосконалити цей код.
Якщо вам просто потрібна ця функціональність і ви хочете використовувати її в більш ніж одному контролері, це нескладний сервіс для відстеження історії маршрутів:
(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;
}
})();
де 'core' у .module ('core') буде назва вашої програми / модуля. Потрібна послуга як залежність від вашого контролера, тоді в контролері ви можете:$scope.routeHistory = RouterTracker.getRouteHistory()
Я відслідковую попередні стани в $ rootScope , тому, коли мені це потрібно, я просто зателефоную нижче рядком коду.
$state.go($rootScope.previousState);
У App.js :
$rootScope.$on('$stateChangeSuccess', function(event, to, toParams, from, fromParams) {
$rootScope.previousState = from.name;
});
Для UI-маршрутизатора (> = 1.0) події StateChange застаріли. Щоб отримати повний посібник з міграції, натисніть тут
Щоб отримати попередній стан поточного стану в 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');
});
});
Дійсно просте рішення - просто відредагувати рядок $ state.current.name і вирізати все, включаючи і після останнього '.' - ви отримуєте ім'я батьківської держави. Це не працює, якщо ви багато стрибаєте між станами, оскільки це просто розбирає поточний шлях. Але якщо ваші штати відповідають тому, де ви є насправді, то це працює.
var previousState = $state.current.name.substring(0, $state.current.name.lastIndexOf('.'))
$state.go(previousState)
$state.go('^')
досягне цього
Ви можете повернути стан таким чином:
$state.go($state.$current.parent.self.name, $state.params);
Приклад:
(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);
};
};
})();