각도-UI 라우터가 이전 상태를 얻습니다.


152

현재 상태의 이전 상태를 얻는 방법이 있습니까?

예를 들어 이전 상태가 현재 상태 B 이전의 상태 (이전 상태는 상태 A였던)를 알고 싶습니다.

ui-router github doc 페이지에서 찾을 수 없습니다.


아래 답변이 정확합니다. 문서가 충분하지 않은 경우 소스에서 필요한 모든 정보를 찾을 수도 있습니다. goo.gl/9B9bH
David Chase

답변:


133

ui-router는 이전 상태가 전환되면 추적하지 않지만 상태가 변경 될 때 이벤트 $stateChangeSuccess가 브로드 캐스트 $rootScope됩니다.

해당 이벤트에서 이전 상태를 잡을 수 있어야합니다 ( from탈퇴 상태).

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

3
"from"을 사용하는 예는 무엇입니까?
Paul

여기서 'to'와 'from'은 'toState'와 'fromState'를 의미합니다. 이전 URL이 localhost : xxxx / employee이고 컨트롤러가 'EmployeesController'인 경우 'fromState'의 예는 다음과 같습니다. Object {url : "/ employees", templateUrl : "/ employees", 컨트롤러 : "EmployeesController", 이름 : " 직원 "}
Ranadheer Reddy

3
나는 내 초록에서 이것을했다 :`$ rootScope.previousState; $ rootScope.currentState; $ rootScope. $ on ( '$ stateChangeSuccess', function (ev, to, toParams, from, fromParams)) {$ rootScope.previousState = from.name; $ rootScope.currentState = to.name; console.log ( '이전 상태 : '+ $ rootScope.previousState) console.log ('현재 상태 : '+ $ rootScope.currentState)}); `rootScope에서 이전과 현재를 추적합니다. 꽤 편리합니다!
Federico

@ endy-tjahjono ( stackoverflow.com/a/25945003/2837519 ) 솔루션을 사용하는 것이 ui-router 1.x의 인라인입니다.
피터 Ahlers

history.back () <a href="javascript:history.back()" class="btn btn-default no-radius">
Serip88

146

새 상태로 이동하기 전에 resolve를 사용하여 현재 상태 데이터를 저장합니다.

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작동 하지만 전역 수준에서 수행되므로 실제로는 거의 필요하지 않습니다.
Pierre Spring

2
나는 동의한다. 이것은 훨씬 더 깨끗합니다. 모두 상태가있는 많은 모듈을 다루는 경우, 모듈의 모듈뿐만 아니라 모든 상태 변경에 대해 $ stateChangeSuccess가 시작됩니다. 이것에 대한 또 다른 투표는 더 나은 해결책입니다.
Jason Buchanan

1
@ Nissassin17 어떤 버전을 사용하십니까? v0.2.15에서 상태를 직접 열 때 $state.currentis 객체는 다음과 같습니다 {name: "", url: "^", views: null, abstract: true}.
Endy Tjahjono

3
참고-다음을 수행해야했습니다. Params : angular.copy ($ state.params)-설명 : UI-Router v 1.0.0-beta 2를 사용하고 있으며이 코드의 Params 부분에 문제가있었습니다. $ state.params는 객체이기 때문에 함수가 해결 된 후 현재보기로 업데이트됩니다 ... 객체가 현재보기에서 업데이트되는 것을 방지하기 위해 resolve 함수 에서이 작업을 수행해야했습니다.
Joe H

100

가독성을 위해 내 솔루션 (stu.salsbury의 답변을 기반으로 함)을 여기에 배치합니다.

이 코드를 앱의 추상 템플릿에 추가하여 모든 페이지에서 실행되도록하십시오.

$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도 저장하는 것이 좋습니다.
Yaron

나는 이것을 좋아하고 내 응용 프로그램에서 구현합니다. 감사합니다
Fallenreaper

정말 유용합니다 ... localStorage를 더 많이 사용하면 어디서나 previousState를 얻을 수 있습니다.
georgeos

14

다음 예제 decorator에서 (구성 단계에서 앱 당 한 번만 실행)을 만들고 $state서비스에 추가 속성을 추가 하므로이 방법은 전역 변수를 추가 $rootscope하지 않으며 다른 서비스에 대한 추가 종속성을 추가 할 필요가 없습니다.$state .

내 예에서는 사용자가 이미 로그인했을 때와 로그인 후 이전 "보호 된"페이지로 리디렉션하지 않을 때 사용자를 색인 페이지로 리디렉션해야했습니다.

내가 사용하는 알려지지 않은 유일한 서비스는 다음 authenticationFactoryappSettings같습니다.

  • authenticationFactory사용자 로그인 만 관리하면됩니다. 이 경우 사용자가 로그인했는지 여부를 식별하는 방법 만 사용합니다.
  • appSettings어디서나 문자열을 사용하지 않는 상수입니다. appSettings.states.loginappSettings.states.register로그인에 대한 국가의 이름을 포함하고 URL을 등록합니다.

그런 다음 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

$ stateChangeStart의 $ state에 {previous}라는 새 속성을 추가하십시오.

$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

URL에 푸시하지 않으면 $ stateParams가 손실됩니다. 더 나은 솔루션은 $ paraScope에 이전 매개 변수를 저장하는 것입니다. 이에 서 가져 와서 $ state로 푸시하면 되돌아 갈 수 있습니다.
dangquang1020

이 답변은 구현하기가 가장 쉽습니다.
Lalnuntluanga Chhakchhuak

8

Endy Tjahjono가하는 것과 비슷한 접근법을 사용합니다.

내가하는 것은 전환하기 전에 현재 상태의 값을 저장하는 것입니다. 예를 보자. 전환을 트리거하는 모든 항목을 클리 킹 할 때 실행되는 함수 내에서 이것을 상상해보십시오.

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

여기서 핵심은 params 객체 (상태로 보내질 매개 변수의 맵)입니다-> { previousState : { name : $state.current.name } }

참고 : Im은 상태를 저장하는 데 필요한 유일한 것이므로 $ state 객체의 이름 속성 만 "저장"한다는 점에 유의하십시오. 그러나 우리는 전체 상태 객체를 가질 수 있습니다.

그런 다음 "whatever"라고 다음과 같이 정의하십시오.

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

여기서 핵심은 params 객체입니다.

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 이전 상태와 fromParams가 이전 상태 매개 변수입니다.


1
2017 년 5 월 16 일, Chris Thielen은 ui-router-extras 프로젝트에 대한 수명 종료 통지 를 추가했습니다.
Michael R

4

좋아, 나는 여기서 파티에 늦었다는 것을 알고 있지만, 나는 각도가 처음이다. John Papa 스타일 가이드에 맞게 만들려고합니다 . 나는 이것을 재사용 가능하게 만들고 싶어서 블록으로 만들었습니다. 다음은 내가 생각해 낸 것입니다.

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

핵심 모듈

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

여기서 .module ( 'core')의 '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
from.name뿐만 아니라 저장하지 않는 것이 좋습니다. 이런 식으로 $ state.go ($ tootScope.previousState.name, $ tootScope.previousState.params);
abelabbesnabi

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('^')이것을 달성 할 것이다
james

그리고 국가 매개 변수는 어떻습니까?
Tushar Shukla

-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 ( "^")를 사용하는 것과 같지 않습니까?
Nathan Moinvaziri 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.