Angular UI-Router,访问父状态并动态地将用户重定向到某个子状态

时间:2014-12-05 14:56:15

标签: angularjs angular-ui angular-ui-router

我通过访问网址http://myapp/validate来获得主要状态。

到达此URL后,在控制器内部进行权限检查,并将用户重定向到两个子状态之一。

这有效,80%满意,但使用了一些资源,并在我的应用程序中引起一个小闪烁,因为基本上我加载了一个我不使用的视图。

有没有更好的方法来实现这一目标?

有什么想法吗?

angular.module('app.validate').config(['$stateProvider', function($stateProvider) {
    $stateProvider
        .state('validate', {
            url: '/validate',
            template: '<ui-view/>',
            controller: ['$state', 'HasPermission', function ($state, HasPermission) {

                // Here is where I do my logic.

                if (HasPermission.get('can-lock-as-admin')) {
                    $state.go('validate.lock-as-admin');
                }

                if (HasPermission.get('can-lock-as-clerk')) {
                    $state.go('validate.lock-as-clerk');
                }
            }]
        })
        .state('validate.lock-as-admin', {
            templateUrl: 'theUrl',
            controller: 'ValidateLockAdminCtrl'
        })
        .state('validate.lock-as-clerk', {
            templateUrl: 'theUrl',
            controller: 'ValidateLockClerkCtrl'
        })
        .state('validate.commit', {
            templateUrl: 'theUrl',
            controller: 'ValidateCommitCtrl'
        });
}]);

3 个答案:

答案 0 :(得分:7)

闪烁的原因是您实际上是让用户在将他移至正确的路径之前访问http://myapp/validate
您可以通过将他重定向到正确的路径而不显示父路由来避免这种情况。

app.run(function($rootScope){

  $rootScope.$on('$stateChangeStart', 
    function(e, toState, toParams, fromState, fromParams), {
      if(toState.name === 'validate') { // some conditional
        e.preventDefault(); // This tells the app not to move to the validate route

        if (HasPermission.get('can-lock-as-admin')) {
           $state.go('validate.lock-as-admin');
        }
        if (HasPermission.get('can-lock-as-clerk')) {
           $state.go('validate.lock-as-clerk');
        }
      }
    });
  });

});  

要想拥有一个更清洁的解决方案,您可以使用resolve块来检查权限,但我不是100%关于此问题,我现在没有时间检查它。
我建议你看一下this article,因为它以一种很好的方式解释了类似的场景。

答案 1 :(得分:0)

如果您不想延长ui-router,我建议如下:

  • 不要创建过渡状态。

    ui-router引擎的运行假设当你指向一个状态并且转换成功时,应该呈现状态的视图。因此,如果您指向一个状态并允许在实际尝试转移到其他地方时解析它,请准备好闪烁。

    这会导致问题“如果我不让状态解决而是重定向怎么办?”。不幸的是,在状态解析过程中,重定向似乎存在一些问题。请参阅休息后的答案部分。

  • 创建后备......

    您可以决定哪个子状态是默认状态并指向该状态,而不是具有单独的过渡状态。在那里,您可以执行检查,并可能在其他地方重定向。在重定向的情况下,这仍然会导致闪烁。但如果您的默认选择是精心选择的,并且重定向只是偶尔发生,那么这是一个良好的开端。

  • ...或直接指向正确的目的地。

    正确使用状态机意味着指向您实际希望用户前往的状态。这意味着在触发状态转换之前,应该执行任何检查。当然,这只有在以编程方式指导时才有可能。您仍然需要先前的“后备”策略来处理用户尝试通过输入其URL来启动特定状态。


或者,您可以将ui-router扩展一下,以便在状态解析期间允许状态转换。 (我上次检查时,您无法安全地从resolve重定向到不同的状态。)例如,您可以装饰$state并在状态解析已经进行时停止重定向尝试(您可以通过观察适当的事件来判断,然后在状态解析完成后重定向到最后捕获的状态。如果你这样做,你可以创建这样的过渡状态:

.state('someTransitionalState', {
    resolve: {
        redirect: ['permissions', '$state', '$q', function (permissions, $state, $q) {
            $state.go(permissions.has(...) ? ... : ...);
            return $q.reject('transitional state - redirected elsewhere');
        }]
    }
})

这样过渡状态永远不会解决,所有到达它的尝试都将导致到达其他选定的目的地。

答案 2 :(得分:0)

您可以在路线上使用一些自定义权限属性,您可以检查,例如:

.state('validate.lock-as-admin', {
            template: '<h1>lock as admin</h1>',
            permission: 'admin',
            otherwise: 'validate.lock-as-clert'
        })
        .state('validate.lock-as-clerk', {
            template: '<h1>lock as clerk</h1>',
            permission: 'clerk',
            otherwise: 'validate.lock-as-admin'
        })

然后你可以观察路线变化并进行一些自定义权限检查。 这是一个例子,如何实现这一目标。 example