Angular - ui-router có được trạng thái trước đó


152

Có cách nào để có được trạng thái trước đó của trạng thái hiện tại không?

Ví dụ tôi muốn biết trạng thái trước là gì trước trạng thái B hiện tại (trong đó trạng thái trước đó sẽ là trạng thái A).

Tôi không thể tìm thấy nó trong các trang tài liệu github của bộ định tuyến.


câu trả lời dưới đây là chính xác, bạn cũng có thể tìm thấy tất cả thông tin bạn cần từ nguồn nếu tài liệu không đủ trợ giúp goo.gl/9B9bH
David Chase

Câu trả lời:


133

ui-router không theo dõi trạng thái trước đó khi nó chuyển tiếp, nhưng sự kiện $stateChangeSuccessđược phát vào $rootScopekhi trạng thái thay đổi.

Bạn sẽ có thể bắt trạng thái trước từ sự kiện đó ( fromlà trạng thái bạn rời đi):

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

3
Điều gì sẽ là một ví dụ sử dụng "từ"?
Paul

Ở đây 'đến' và 'từ' có nghĩa là 'toState' và 'fromState'. Hãy xem xét url trước đó của bạn là localhost: xxxx / staff và bộ điều khiển là 'Emp EmployControll', ví dụ cho 'fromState' là: Object {url: "/ staff", templateUrl: "/ staff", bộ điều khiển: "Emp EmployControll", name: " nhân viên "}
Ranadheer Reddy

3
Tôi đã làm điều này trong bản tóm tắt của mình: `$ rootScope.preinglyState; $ rootScope.cienState; $ rootScope. $ on ('$ stateChangeSuccess', function (ev, to, toParams, from, fromParams) {$ rootScope.preinglyState = from.name; $ rootScope.civerseState = to.name; console.log ('Trạng thái trước: '+ $ rootScope.preinglyState) console.log (' Trạng thái hiện tại: '+ $ rootScope.civerseState)}); `Nó theo dõi trước và hiện tại trong rootScope. Khá tiện dụng!
Federico

Sử dụng giải pháp của @ endy-tjahjono ( stackoverflow.com/a/25945003/2837519 ) là nội tuyến hơn của ui-router 1.x.
Peter Ahlers

Tôi yêu một cách đơn giản với history.back () <a href="javascript:history.back()" class="btn btn-default no-radius">
Serip88

146

Tôi sử dụng giải quyết để lưu dữ liệu trạng thái hiện tại trước khi chuyển sang trạng thái mới:

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
tốt hơn nhiều so với đối phó với$stateChangeSuccess
SET

10
Theo tôi, đây nên là câu trả lời được chấp nhận. Sự kiện mặc dù $stateChangeSuccesshoạt động, nó thực hiện nó ở cấp độ toàn cầu, điều không thực sự cần thiết hầu hết thời gian.
Pierre Spring

2
Tôi đồng ý. Điều này là sạch sẽ hơn nhiều. Nếu bạn đang xử lý nhiều mô-đun mà tất cả đều có trạng thái, $ stateChangeSuccess sẽ bị loại bỏ cho mọi thay đổi trạng thái, không chỉ các mô-đun trong mô-đun của bạn. Một phiếu khác cho điều này là giải pháp tốt hơn.
Jason Hội nguyên

1
@ Nissassin17 bạn sử dụng phiên bản nào? Trong v0.2.15 khi mở trạng thái trực tiếp $state.currentlà đối tượng : {name: "", url: "^", views: null, abstract: true}.
Endy Tjahjono

3
FYI - Tôi cần thực hiện các thao tác sau: Params: angular.copy ($ state.params) - Giải thích: Tôi đang sử dụng UI-Router v 1.0.0-beta 2 và tôi gặp vấn đề với phần Params của mã này; bởi vì $ state.params là một đối tượng, nó sẽ cập nhật lên chế độ xem hiện tại sau khi chức năng được giải quyết ... tôi cần phải làm điều này trong chức năng giải quyết để ngăn đối tượng được cập nhật trong chế độ xem hiện tại.
Joe H

100

Để dễ đọc, tôi sẽ đặt giải pháp của mình (dựa trên stu.salsbury's anwser) tại đây.

Thêm mã này vào mẫu trừu tượng của ứng dụng để nó chạy trên mọi trang.

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

Theo dõi các thay đổi trong rootScope. Nó khá tiện dụng.


19
Cũng đáng để lưu trữ từParams nếu bạn thực sự muốn chuyển hướng ai đó trở lại nơi họ đến.
Yaron

Tôi thích điều này và thực hiện nó trong các ứng dụng của tôi. Cảm ơn
Fallenreaper

Thực sự hữu ích ... Thậm chí nhiều hơn bằng cách sử dụng localStorage, bạn có thể nhận đượcState trước đó ở bất cứ đâu.
georgeos

14

Trong ví dụ sau tôi đã tạo một decorator(chỉ chạy một lần cho mỗi ứng dụng ở giai đoạn cấu hình) và thêm một thuộc tính bổ sung cho $statedịch vụ, vì vậy cách tiếp cận này không thêm các biến toàn cục vào $rootscopevà không yêu cầu thêm bất kỳ phụ thuộc nào vào các dịch vụ khác ngoài $state.

Trong ví dụ của tôi, tôi cần chuyển hướng người dùng đến trang chỉ mục khi anh ta đã đăng nhập và khi anh ta không chuyển hướng anh ta đến trang "được bảo vệ" trước đó sau khi đăng nhập.

Các dịch vụ không xác định duy nhất (cho bạn) mà tôi sử dụng là authenticationFactoryappSettings:

  • authenticationFactorychỉ quản trị đăng nhập người dùng. Trong trường hợp này tôi chỉ sử dụng một phương pháp để xác định xem người dùng có đăng nhập hay không.
  • appSettingslà hằng số chỉ để không sử dụng chuỗi ở khắp mọi nơi. appSettings.states.loginappSettings.states.registerchứa tên của tiểu bang cho url đăng nhập và đăng ký.

Sau đó, trong bất kỳ controller/ serviceetc bạn cần tiêm $statedịch vụ và bạn có thể truy cập url hiện tại và trước đó như thế này:

  • Hiện hành: $state.current.name
  • Trước: $state.previous.route.name

Từ bảng điều khiển Chrome:

var injector = angular.element(document.body).injector();
var $state = injector.get("$state");
$state.current.name;
$state.previous.route.name;

Thực hiện:

(Tôi đang sử dụng angular-ui-router v0.2.17angularjs 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

Thêm một thuộc tính mới được gọi là {trước} vào $ state trên $ 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;
    ...
}

Bây giờ bất cứ nơi nào bạn cần đều có thể sử dụng $ state bạn sẽ có sẵn trước đó

previous:Object
    name:"route name"
    params:Object
        someParam:"someValue"
    resolve:Object
    template:"route template"
    url:"/route path/:someParam"

Và sử dụng nó như vậy:

$state.go( $state.previous.name, $state.previous.params );

9

Tôi bị mắc kẹt với cùng một vấn đề và tìm cách dễ nhất để làm điều này ...

//Html
<button type="button" onclick="history.back()">Back</button>

HOẶC LÀ

//Html
<button type="button" ng-click="goBack()">Back</button>

//JS
$scope.goBack = function() {
  window.history.back();
};

(Nếu bạn muốn nó dễ kiểm tra hơn, hãy đưa dịch vụ $ window vào bộ điều khiển của bạn và sử dụng $ window.history.back ()).


nó phức tạp hơn khi bạn có menu trong ứng dụng của mình
Swanand

không gặp vấn đề của bạn, vui lòng cung cấp thêm chi tiết
NiRmaL

Bạn sẽ mất $ stateParams nếu bạn không đẩy nó vào url, giải pháp tốt hơn là lưu các thông số trước đó của bạn vào $ rootScope, bạn có thể lấy nó từ đó và đẩy vào trạng thái $ để quay lại.
dangquang1020

Câu trả lời này là dễ nhất đối với tôi để thực hiện.
Lalnuntluanga Chhakchhuak

8

Tôi sử dụng một cách tiếp cận tương tự như những gì Endy Tjahjono làm.

Những gì tôi làm là để lưu giá trị của trạng thái hiện tại trước khi thực hiện chuyển đổi. Hãy xem trên một ví dụ; hãy tưởng tượng điều này bên trong một hàm được thực thi khi bám vào bất cứ thứ gì kích hoạt quá trình chuyển đổi:

$state.go( 'state-whatever', { previousState : { name : $state.current.name } }, {} );

Chìa khóa ở đây là đối tượng params (bản đồ các tham số sẽ được gửi đến trạng thái) -> { previousState : { name : $state.current.name } }

Lưu ý: lưu ý rằng tôi chỉ "lưu" thuộc tính tên của đối tượng $ state, vì đó là điều duy nhất tôi cần để lưu trạng thái. Nhưng chúng ta có thể có toàn bộ đối tượng nhà nước.

Sau đó, nói "bất cứ điều gì" được định nghĩa như thế này:

.state( 'user-edit', {
  url : 'whatever'
  templateUrl : 'whatever',
  controller: 'whateverController as whateverController',
  params : {
    previousState: null,
  }
});

Ở đây, điểm chính là đối tượng params.

params : {
  previousState: null,
}

Sau đó, bên trong trạng thái đó, chúng ta có thể có trạng thái trước đó như sau:

$state.params.previousState.name

6

Đây là một giải pháp thực sự tao nhã từ Chris Thielen ui-router-extend: $ trướcState

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

previouslà một đối tượng trông giống như: { state: fromState, params: fromParams }trong đó fromState là trạng thái trước và fromParams là các tham số trạng thái trước đó.


1
Vào ngày 16 tháng 5 năm 2017, Chris Thielen đã thêm Thông báo kết thúc cuộc sống cho dự án: ui-router-ngoại vi.
Michael R

4

Ok, tôi biết rằng tôi đến bữa tiệc muộn ở đây, nhưng tôi mới đến góc cạnh. Tôi đang cố gắng làm cho điều này phù hợp với hướng dẫn phong cách John Papa ở đây. Tôi muốn làm điều này có thể tái sử dụng vì vậy tôi đã tạo trong một khối. Đây là những gì tôi đã đưa ra:

trướcStateProvider

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

lõi.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
}
})();

Bất kỳ phê bình nào về mã này sẽ chỉ giúp tôi, vì vậy vui lòng cho tôi biết nơi tôi có thể cải thiện mã này.


2

Nếu bạn chỉ cần chức năng này và muốn sử dụng nó trong nhiều bộ điều khiển, đây là một dịch vụ đơn giản để theo dõi lịch sử tuyến đường:

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

trong đó 'lõi' trong .module ('lõi') sẽ là tên của ứng dụng / mô-đun của bạn. Yêu cầu dịch vụ như một sự phụ thuộc vào bộ điều khiển của bạn, sau đó trong bộ điều khiển của bạn, bạn có thể làm:$scope.routeHistory = RouterTracker.getRouteHistory()


4
Nếu tôi có một nút điều hướng trên trang của mình chuyển sang trạng thái trước đó trong lịch sử, sau khi điều hướng đến trạng thái trước đó, stateChangeSuccess sẽ bị loại bỏ để thêm nó vào lịch sử. Vì vậy, mã này sẽ kết thúc dẫn đến một vòng lặp vô tận qua lại giữa 2 trang?
whatsTheDiff

1

Tôi theo dõi các trạng thái trước đó trong $ rootScope , vì vậy bất cứ khi nào tôi cần, tôi sẽ chỉ cần gọi dòng mã dưới đây.

$state.go($rootScope.previousState);

Trong App.js :

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

1
Tôi nghĩ sẽ tốt hơn nếu bạn tiết kiệm không chỉ từ.name. Bằng cách đó, bạn cũng sẽ có các thông số, trong trường hợp bạn cần phải làm một cái gì đó như $ state.go ($ tootScope.preinglyState.name, $ tootScope.preinglyState.params);
abelabbesnabi

0

Đối với Bộ định tuyến UI (> = 1.0), các sự kiện StateChange đã không được chấp nhận. Để có hướng dẫn di chuyển hoàn chỉnh, bấm vào đây

Để có trạng thái trước đó của trạng thái hiện tại trong 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

Một giải pháp thực sự đơn giản là chỉ cần chỉnh sửa chuỗi $ state.cản.name và cắt bỏ mọi thứ kể cả sau và cuối '.' - bạn có được tên của trạng thái cha mẹ. Điều này không hoạt động nếu bạn nhảy nhiều giữa các trạng thái vì nó chỉ phân tích lại đường dẫn hiện tại. Nhưng nếu trạng thái của bạn tương ứng với nơi bạn thực sự ở, thì điều này hoạt động.

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

1
$state.go('^')sẽ hoàn thành việc này
james

Và những gì về các thông số nhà nước?
Tushar Shukla

-2

Bạn có thể trả lại trạng thái theo cách này:

$state.go($state.$current.parent.self.name, $state.params);

Một ví dụ:

(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
Đó không phải là một câu trả lời tốt nếu bạn đang truy cập vào trạng thái từ trạng thái không phải là cha mẹ. Nếu bạn chỉ muốn cha mẹ của trạng thái hiện tại, nó thực hiện công việc.
Maxime Lafarie

1
Đây không giống như sử dụng $ state.go ("^") sao?
Nathan Moinvaziri
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.