Кутовий - ui-роутер отримують попередній стан


152

Чи є спосіб отримати попередній стан поточного стану?

Наприклад, я хотів би знати, яким був попередній стан до поточного стану B (де попередній стан був би станом A).

Я не в змозі знайти його на сторінках doc uc-router github.


відповідь нижче правильна, ви також можете знайти всю необхідну інформацію з джерела, якщо документи недостатньо допомогти goo.gl/9B9bH
Девід Чейз

Відповіді:


133

ui-роутер не відстежує попередній стан, коли він переходить, але подія $stateChangeSuccessтранслюється на $rootScopeмомент зміни стану.

Ви повинні мати можливість спіймати попередній стан цієї події ( fromце стан, який ви залишаєте):

$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
   //assign the "from" parameter to something
});

3
Що може бути прикладом використання "від"?
Пол

Тут 'до' і 'від' означає 'toState' і 'fromState'. Вважайте, що ваша попередня URL-адреса є localhost: xxxx / співробітник, а контролер - 'EmployeesController', то прикладом для 'fromState' є: Об'єкт {url: "/ службовці", templateUrl: "/ службовці", контролер: "EmployeesController", ім'я: " співробітників "}
Ранадхед Редді

3
Я зробив це у своєму рефераті: `$ rootScope.previousState; $ rootScope.currentState; $ rootScope. $ on ('$ stateChangeSuccess', функція (ev, to, toParams, від, fromParams) {$ rootScope.previousState = from.name; $ rootScope.currentState = to.name; console.log ('Попередній стан: '+ $ rootScope.previousState) console.log (' Поточний стан: '+ $ rootScope.currentState)}); `Він відстежує попередні та поточні в rootScope. Досить зручно!
Федеріко

Використовуючи рішення @ Endy-tjahjono ( stackoverflow.com/a/25945003/2837519 ) більш інлайн з UI-маршрутизатор 1.Х.
Пітер Алерс

Я люблю простий спосіб з history.back () <a href="javascript:history.back()" class="btn btn-default no-radius">
Serip88

146

Я використовую рішення для збереження даних поточного стану перед переходом у новий стан:

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;
                }]
            }
        });
}]);

8
набагато краще, ніж мати справу$stateChangeSuccess
SET

10
На мою думку, це має бути прийнятою відповіддю. Подія хоч і $stateChangeSuccessпрацює, але це робиться на глобальному рівні, що не дуже потрібне більшість часу.
П’єр Весна

2
Я згоден. Це набагато чистіше. Якщо ви маєте справу з багатьма модулями, у яких є всі стани, $ stateChangeSuccess буде випущено за кожну зміну стану, а не тільки в модулі. Ще один голос за це - краще рішення.
Джейсон Бюкенан

1
@ Nissassin17, яку версію ви використовуєте? У v0.2.15 при відкритті стану Безпосередньо $state.currentє об'єктом: {name: "", url: "^", views: null, abstract: true}.
Endy Tjahjono

3
FYI - мені потрібно було зробити наступне: Params: angular.copy ($ state.params) - Пояснення: я використовую UI-Router v 1.0.0-beta 2, і у мене виникли проблеми з частиною Params цього коду; оскільки $ state.params є об'єктом, він буде оновлений до поточного виду після того, як функція буде вирішена ... Мені потрібно було це зробити у функції дозволу, щоб запобігти оновленню об'єкта в поточному представленні.
Джо Н

100

Заради читабельності я розміщу тут своє рішення (засноване на прихильнику сту.сальсбері).

Додайте цей код до абстрактного шаблону програми, щоб він працював на кожній сторінці.

$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. Це досить зручно.


19
Також варто зберігати програму fromParams, якщо ви дійсно хочете перенаправити когось туди, звідки вони прийшли.
Ярон

Я люблю це і впроваджую це у своїх додатках. Спасибі
Fallenreaper

Дійсно корисно ... Навіть більше, використовуючи localStorage, ви можете отримати попередній стан де завгодно.
georgeos

14

У наступному прикладі я створив decorator(працює лише один раз на додаток на етапі конфігурації) і додає додаткову властивість до $stateсервісу, тому цей підхід не додає глобальних змінних до $rootscopeі не вимагає додавання додаткової залежності до інших служб, ніж $state.

У моєму прикладі мені потрібно було перенаправити користувача на індексну сторінку, коли він уже був увійшов і коли він не мав перенаправляти його на попередню "захищену" сторінку після входу.

Єдині невідомі сервіси (для вас), якими я користуюся, є authenticationFactoryіappSettings :

  • authenticationFactoryпросто керує логіном користувача. У цьому випадку я використовую лише метод, щоб визначити, чи користувач увійшов чи ні.
  • appSettingsє константами просто для того, щоб не використовувати рядки всюди. appSettings.states.loginі appSettings.states.registerмістять ім'я штату для реєстрації та реєстрації.

Тоді в будь-який controller/ serviceetc вам потрібно ввести $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);

12

Додайте нову властивість під назвою {попередній} до $ 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 );

9

Я застряг у тому ж питанні і знаходжу найпростіший спосіб зробити це ...

//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 ()).


це складніше, коли у вашій заяві є меню
Swanand

не отримуючи вашої проблеми, будь ласка, надайте детальніше
NiRmaL

Ви втратите $ stateParams, якщо не натиснете його на url, кращим рішенням буде зберегти свої попередні парами в $ rootScope, ви можете отримати це з цього і натиснути в стан $, щоб повернутися назад.
dangquang1020

Цю відповідь мені найлегше реалізувати.
Lalnuntluanga Chhakchhuak

8

Я використовую подібний підхід до того, що робить Енді Тяджоно.

Що я роблю, це зберегти значення поточного стану перед тим, як зробити перехід. Подивимось на прикладі; уявіть це всередині функції, що виконується при натисканні на те, що викликає перехід:

$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

6

Ось справді елегантне рішення від Chris Thielen ui-router-extras: $ previousState

var previous = $previousState.get(); //Gets a reference to the previous state.

previousце об'єкт, який виглядає так: { state: fromState, params: fromParams }де fromState - попередній стан, а зParams - попередні параметри стану.


1
16 травня 2017 року Кріс Тілен додав до проекту повідомлення про закінчення життя : ui-router-extras.
Майкл Р

4

Гаразд, я знаю, що я спізнююсь на вечірку тут, але я новачок. Я намагаюся зробити це вписаним у посібник зі стилю Джона Папи тут. Я хотів зробити це для багаторазового використання, тому створив у блоці. Ось що я придумав:

попередній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
}
})();

Будь-яка критика щодо цього коду допоможе лише мені, тому, будь ласка, дайте мені знати, де я можу вдосконалити цей код.


2

Якщо вам просто потрібна ця функціональність і ви хочете використовувати її в більш ніж одному контролері, це нескладний сервіс для відстеження історії маршрутів:

  (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()


4
Якби на моїй сторінці була навігаційна кнопка, яка переходить до попереднього стану в історії, після переходу до цього попереднього стану буде випущено stateChangeSuccess, який додасть її до історії. Так чи не закінчився цей код, що призведе до нескінченного циклу повернення назад і назад між двома сторінками?
whatsTheDiff

1

Я відслідковую попередні стани в $ rootScope , тому, коли мені це потрібно, я просто зателефоную нижче рядком коду.

$state.go($rootScope.previousState);

У App.js :

$rootScope.$on('$stateChangeSuccess', function(event, to, toParams, from, fromParams) {
  $rootScope.previousState = from.name;
});

1
Я думаю, що краще, якщо ви заощадите не лише з .name. Таким чином, у вас будуть також парами, якщо вам потрібно зробити щось на зразок $ state.go ($ tootScope.previousState.name, $ tootScope.previousState.params);
абелаббеснабі

0

Для 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');
    });
});

-1

Дійсно просте рішення - просто відредагувати рядок $ state.current.name і вирізати все, включаючи і після останнього '.' - ви отримуєте ім'я батьківської держави. Це не працює, якщо ви багато стрибаєте між станами, оскільки це просто розбирає поточний шлях. Але якщо ваші штати відповідають тому, де ви є насправді, то це працює.

var previousState = $state.current.name.substring(0, $state.current.name.lastIndexOf('.'))
$state.go(previousState)

1
$state.go('^')досягне цього
Джеймс

А як щодо державних парам?
Тушар Шукла

-2

Ви можете повернути стан таким чином:

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

    };

})();

2
Це не є гарною відповіддю, якщо ви отримуєте доступ до штату з не батьківського. Якщо ви просто хочете батька поточного стану, він робить свою роботу.
Максим Лафарі

1
Чи це не те саме, що використання $ state.go ("^")?
Натан Моінвазірі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.