Angular-ui-routerは以前の状態を取得します


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"、controller: "EmployeesController"、name: "従業員」}
Ranadheer Reddy 2013

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(' Current state: '+ $ rootScope.currentState)}); `以前と現在のルートスコープを追跡します。かなり便利!
フェデリコ

@ endy-tjahjonoのソリューション(stackoverflow.com/a/25945003/2837519)を使用すると、ui-router 1.xのインライン化が向上します。
Peter Ahlers、2017年

私は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は、モジュール内のものだけでなく、すべての状態変化に対して発生します。これに対する別の投票はより良い解決策です。
ジェイソンブキャナン

1
@ Nissassin17どのバージョンを使用していますか?v0.2.15では、状態を直接開くと、$state.currentisオブジェクト:になり{name: "", url: "^", views: null, abstract: true}ます。
Endy Tjahjono 2016年

3
参考までに、次のことを行う必要がありました。Params:angular.copy($ state.params)-説明:UI-Router v 1.0.0-beta 2を使用していますが、このコードのParams部分に問題がありました。$ state.paramsはオブジェクトなので、関数が解決された後、現在のビューに更新されます...現在のビューでオブジェクトが更新されないようにするには、resolve関数でこれを行う必要がありました。
ジョーH

100

読みやすくするために、ここにソリューション(stu.salsburyのanwserに基づく)を配置します。

このコードをアプリの抽象テンプレートに追加して、すべてのページで実行できるようにします。

$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、2015

私はこれが大好きで、自分のアプリケーションに実装しています。ありがとう
Fallenreaper

本当に便利... localStorageを使用すれば、どこでもpreviousStateを取得できます。
georgeos 2017

14

次の例では、decorator(設定フェーズでアプリごとに1回だけ実行される)を作成し、$stateサービスに追加のプロパティを追加します。そのため、このアプローチではグローバル変数$rootscopeが追加されず、以外のサービスに追加の依存関係を追加する必要はありません$state

私の例では、ユーザーが既にサインインしている場合と、サインイン後にユーザーを以前の「保護された」ページにリダイレクトしない場合に、ユーザーをインデックスページにリダイレクトする必要がありました。

私が使用して(あなたのための)唯一の未知のサービスがあるauthenticationFactoryappSettings

  • authenticationFactoryユーザーのログインを管理するだけです。この場合、ユーザーがログインしているかどうかを識別する方法のみを使用します。
  • appSettingsどこでも文字列を使用しないための定数です。appSettings.states.loginそしてappSettings.states.registerログインの状態の名前が含まれているとURLを登録します。

次に、任意のcontroller/ serviceなどで$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()を使用してください)。


アプリケーションにメニューがある場合は、より複雑になります。
スワンナンド

問題が解決しない場合は、詳細を
お知らせ

URLにプッシュしないと$ stateParamsが失われます。以前のパラメーターを$ rootScopeに保存すると、それを取得して、$ stateにプッシュして戻ることができます。
dangquang1020 2017

この答えは、私が実装するのが最も簡単です。
Lalnuntluanga Chhakchhuak

8

私は、Endy Tjahjonoと同じようなアプローチをとっています。

私が行うことは、遷移を行う前に現在の状態の値を保存することです。例を見てみましょう。トランジションをトリガーするものにクリックしたときに実行される関数の内部を想像してみてください。

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

ここで重要なのはparamsオブジェクト(状態に送信されるパラメーターのマップ)です-> { previousState : { name : $state.current.name } }

注:状態を保存するために必要なのは、Imだけが$ stateオブジェクトの名前属性を「保存」することに注意してください。しかし、状態オブジェクト全体を持つことができます。

次に、「何でも」という状態を次のように定義します。

.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のサポート終了のお知らせを追加しました。
マイケルR

4

わかりました、私はここのパーティーに遅れるのを知っています、しかし私は角張ったことが初めてです。これをジョンパパスタイルガイドに合わせるようにしています。これを再利用可能にしたかったので、ブロックで作成しました。これが私が思いついたものです:

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

このコードへの批判は私を助けるだけなので、このコードをどこで改善できるか教えてください。


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が発生し、履歴に追加されます。それで、このコードは、2ページ間を行き来する無限ループに終わってしまうのではないでしょうか?
whatsTheDiff 2016年

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);のようなことをする必要がある場合に備えて、paramsも持つことになります。
abelabbesnabi

0

UI-Router(> = 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('^')これを達成します
ジェームズ2016年

そして、状態パラメータはどうですか?
Tushar Shukla 2017

-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
非親状態から状態にアクセスしている場合、これは良い答えではありません。現在の状態の親だけが必要な場合は、それが機能します。
Maxime Lafarie、2016

1
これは$ state.go( "^")を使用するのと同じではありませんか?
Nathan Moinvaziri 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.