Verifying route preconditions prior to loading controller

China☆狼群 提交于 2019-12-21 04:22:34

问题


I'm writing a single page application in Angular, specifically angular.dart, but I'm assuming this question still applies to AngularJS.

Take for example the following routes:

/login - Expects nobody to be logged in. If someone is authenticated but not registered, redirect to "register" route, if they are registered, redirect to the "home" route.

/register - Expects an authenticated user who hasn't finished the registration process. If not authenticated, redirect to login. If is authenticated, redirect to home.

/home - Expects an authenticated and registered user. If not authenticated, redirect to "login" route, if not registered, redirect to "register" route.

I've done quite a bit of searching but cannot find a built-in or idiomatic way to check to make sure that certain preconditions are met before loading the controller associated with a particular route, and to redirect appropriately when these preconditions are not met.

Any help would be greatly appreciated!


回答1:


Angular.Dart and Angular.JS routing frameworks are very/fundamentally different. Angular.Dart is using a third party routing framework (https://github.com/dart-lang/route/tree/experimental_hierarchical) and only implements angular specific features like ng-view and ways to bind routes to templates via ViewFactory.

So your question really falls into the route_hierarchical package domain. Currently you can veto users attempt to navigate away from a route, but I guess what you want the ability to veto user entering a route depending on if the user is logged in or not. Unfortunately this is not yet supported, but is planned.

What you could try in the meantime is creating a custom viewFactory wrapper.

class RecipesRouteInitializer implements RouteInitializer {
   void init(Router router, ViewFactory view) {
     router
       ..addRoute(
          name: 'login',
          path: '/login',
          enter: authView(router, view('login.html'), NOT_AUTH))
       ..addRoute(
          name: 'register',
          path: '/register',
          enter: authView(router, view('register.html'), AUTH_NO_REG))
       ..addRoute(
          name: 'home',
          path: '/home',
          enter: authView(router, view('home.html'), AUTH_AND_REG));
   }

   authView(Router router, ngView, mode) {
     return (RouteEvent e) {
       if (mode == AUTH_AND_REG) {
         if (!authService.isAuth) {
           router.go('login', {});
           return;
         }
         if (!authService.isReg) {
           router.go('register', {});
           return;
         }
       } else if (mode == AUTH_NO_REG) {
         if (!authService.isAuth) {
           router.go('login', {});
           return;
         }
         if (authService.isReg) {
           router.go('home', {});
           return;
         }
       } else if (mode == NOT_AUTH) {
         if (authService.isAuth) {
           router.go('register', {});
           return;
         }
       }
       ngView(e);
     };
   }

}

DISCLAMER: this is just an idea... might totally not work.




回答2:


Well, I made a thing in Dart which is close to one of the previous solutions which don't really work. The main point is that in the RouteEventHandler, you need to call the RouteEventHandler of the view.

      ..addRoute(
          name: 'userAdd',
          path: '/userAdd',
          enter: checkAuthentication(router,view,'view/addUser.html'))
      ..addRoute(
        name: 'login',
        path: '/login',
        enter: view('view/login.html'));
  }

  RouteEventHandler checkAuthentication(Router router,ViewFactory view, String location){
     return (RouteEvent e) {
      if(_authenticationService.isAuthenticated()){
        view(location)(e);
      }else{
        router.go("login",{});
      }
    };
  }



回答3:


Note: this applies to AngularJS only, leaving this up in case someone using JS needs it.

Take a look at the resolve property in $routeProvider. You can return a promise which will determine whether the route change should be accepted or not.

From the docs:

If any of these dependencies are promises, the router will wait for them all to be resolved or one to be rejected before the controller is instantiated. If all the promises are resolved successfully, the values of the resolved promises are injected and $routeChangeSuccess event is fired. If any of the promises are rejected the $routeChangeError event is fired.

There's also a video about it and the route lifecycle on egghead.io here




回答4:


I know that following solution is not applicable to Angular.Dart, but still is worth to mention solution for ui-router:

https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-create-rules-to-prevent-access-to-a-state

app.config(function($stateProvider) {
  $stateProvider.state('privatePage', {
  data: {
    rule: function(user) {
    // ...
  }
});
});
app.run(function($rootScope, $state, $currentUser) {
$rootScope.$on('$stateChangeStart', function(e, to) {
if (!angular.isFunction(to.data.rule)) return;
var result = to.data.rule($currentUser);

if (result && result.to) {
  e.preventDefault();
  // Optionally set option.notify to false if you don't want 
  // to retrigger another $stateChangeStart event
  $state.go(result.to, result.params, {notify: false});
}
});
});


来源:https://stackoverflow.com/questions/20429997/verifying-route-preconditions-prior-to-loading-controller

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!