web-dev-qa-db-ja.com

AngularJS-$ routeChangeStartと$ locationChangeStartの組み合わせが必要です

私の問題は、実際にここにある問題と非常によく似ています。

AngularJs-ルート変更イベントのキャンセル

つまり、$ routeChangeStartを使用し、$ locationを使用して現在のルートを変更しようとしています。実行すると、元のページがまだ読み込まれていて、新しいページですぐに上書きされることがコンソールに表示されます。

提供された解決策は、$ routeChangeStartの代わりに$ locationChangeStartを使用することでした。これは、余分なリダイレクトを防ぐために機能するはずです。残念ながら、ルートを変更する際にアクセスする必要がある追加のデータを$ routeproviderで使用しています(ページの制限を追跡するために使用しています)。以下に例を示します...

$routeProvider.
    when('/login', { controller: 'LoginCtrl', templateUrl: '/app/partial/login.html', access: false}).
    when('/home', { controller: 'HomeCtrl', templateUrl: '/app/partial/home.html', access: true}).
    otherwise({ redirectTo: '/login' });


$rootScope.$on('$routeChangeStart', function(event, next, current) {
    if(next.access){
        //Do Stuff
    }
    else{
        $location.path("/login");
        //This will load the current route first (ie: '/home'), and then
        //redirect the user to the correct 'login' route.
    }
});

$ routeChangeStartを使用すると、「next」および「current」パラメーター( AngularJS-$ route を参照)をオブジェクトとして使用して、「アクセス」値を取得できます。 $ locationChangeStartを使用すると、これらの2つのパラメーターはオブジェクトではなくURL文字列を返します。したがって、「アクセス」値を取得する方法はないようです。

$ locationChangeStartのリダイレクト停止力と$ routeChangeStartのオブジェクトの柔軟性を組み合わせて、必要なものを実現する方法はありますか?

21
ThisLanham

頭に浮かぶ1つのアプローチは、このためにresolveパラメーターを使用しようとすることです。

var resolver = function(access) {
  return {
    load: function($q) {
      if (access) { // fire $routeChangeSuccess
        var deferred = $q.defer();
        deferred.resolve();
        return deferred.promise;
      } else { // fire $routeChangeError
        return $q.reject("/login");
      }
    }
  }
}

$routeProvider.
  when('/login', { controller: 'LoginCtrl', templateUrl: '/app/partial/login.html', resolve: resolver(false)}).
  when('/home', { controller: 'HomeCtrl', templateUrl: '/app/partial/home.html', resolve: resolver(true)}).
  otherwise({ redirectTo: '/login' });

上記のコードはテストしていませんが、プロジェクトで同様のことを行っていることに注意してください。

21
Marius Soutier

私自身も同じ状況に直面し、私の解決策はOPの意図と一致していました。

$locationChangeStartイベントと$routeサービスを使用します。 $route.routesにアクセスすることで、$routeProviderで定義されたすべてのルートオブジェクトを取得できます。

.run(function($rootScope, $route, $location) {
  $rootScope.$on('$locationChangeStart', function(ev, next, current) {
    // We need the path component of `next`. We can either process `next` and 
    // spit out its path component, or simply use $location.path(). I go with
    // the latter.
    var nextPath = $location.path();
    var nextRoute = $route.routes[nextPath]

    console.log(nextRoute.access); // There you go!
  });
})

絶対URLからパスコンポーネントを解析するには:

var urlParsingNode = document.createElement('a');
urlParsingNode.href = next;  // say, next = 'http://www.abc.com/foo?name=joe
console.log(urlParsingNode.pathname)  // returns "/foo"
14
tamakisquare

バージョン1.3.0以降では、新しく導入された preventDefault -methodを実際に使用できます。これにより、現在のルートの変更をキャンセルし、次のように独自のカスタムリダイレクトを適用できます github-issue


$rootScope.$on("$routeChangeStart", function (event, next, current) {
    if (next.access) {
      event.preventDefault();
      $rootScope.$evalAsync(function() {
        $location.path('/login');
      });
    }
});

このメソッドを自分のプロジェクトに実装しましたが、完全に機能します。それがつまずく他の誰にも役立つことを願っています。

7
snrlx

いい答えマリウス、私を正しい方向に導いた。私はアクセス制御のためにこのようなことをしています。ただし、これは機能します...

  var resolver = function(route, routeEvent) {
  return {
    load: function($q) {
      deferred = $q.defer();
      if (routeEvent!=3) { // eventually will be a list of routeEvents that the logged-in user is not allowed to visit read from a db table configured by admin
        deferred = $q.defer();
        deferred.resolve();
        return deferred.promise;
      } else { // fire $routeChangeError
        alert("You don't have permissions to access this.");
        deferred.reject(route);
        return deferred.promise;
      }
    }
  }
}

  var jsonRoutes = [

    {'route' : '/logout', 'templateUrl': 'partials/login.html',   'controller' : 'LoginCtrl', 'routeEvent' : 1 },
    {'route' : '/orders', 'templateUrl': 'partials/orders.html',   'controller': 'OrderListCtrl', 'routeEvent' : 2 },
    {'route' : '/products', 'templateUrl': 'partials/products.html',   'controller': 'ProductListCtrl', 'routeEvent' : 3 },

...

];


// somewhere on successful login code add in the dynamic routes

angular.forEach(jsonRoutes, function(r) {
                $route.routes[r.route] = {templateUrl: r.templateUrl, controller: r.controller, routeEvent: r.routeEvent, resolve: resolver(r.route, r.routeEvent)};
                  });


// got some static routes too which don't have access control - user has to login right?

  config(['$routeProvider', function($routeProvider) {


  $routeProvider.
    when('/error',  {templateUrl: 'partials/error.html',   controller : ErrorCtrl,  routeEvent : 1 }).
    when('/login',  {templateUrl: 'partials/login.html',   controller : LoginCtrl, routeEvent : 1 }).
    when('/home',  {templateUrl: 'partials/home.html',   controller : HomeCtrl, routeEvent : 1 }).
    when('/logout', {templateUrl: 'partials/login.html',   controller : LoginCtrl, routeEvent : 1 }).
    otherwise( {redirectTo: '/error'} );   

/ ordersルートがクリックされると、約束は拒否され(ポップアップが表示され、モーダルダイアログになる可能性があります)、ルートは追跡されません。

これが誰かを助けることを願っています。

3
Nick