angular-ui-router:解析根状态

时间:2014-05-21 16:02:52

标签: angularjs angular-ui-router

据我了解ui.router

你有$ stateProvider

在其中你可以写$ stateProvider.state()

你可以写

    .state('account', {
        url: '/account',
        template: '<ui-view/>'
    })
    .state('account.register', {
        url: '/register',
        templateUrl: '/account/views/register.html',
        data: { title: 'Create Account' },
        controller: 'AccountRegister'
    })

但'account'是某种根状态的孩子。

所以我的想法是,ui.router的根状态有一个<ui-view/>,就像'account'有模板'<ui-view/>'一样,所以index.html就是根状态。即使是'home' url: '/'$http.get('/api/user/status')也会是这个根状态的孩子。

如果我能够访问根状态并说它应解析用户服务,则此解析值应该在所有状态上可用(或者更好地在每个状态是根状态的子状态,也就是所有状态)。用户服务承诺生成{"user":{id: "userid", role: "role"}} or {"user":null}并返回User.get() 这将保证始终填充用户服务返回的值。

如何访问根状态并说它应该解决,例如{{1}}?

或者让我重新说一下。

所有控制器都应该可以使用用户对象。 有关当前登录用户的信息由$ http.get('/ api / user / status')提供 这就是问题,我正在寻找一个DRY解决方案,假设api正在服务,假设用户对象设置是100%安全,也就是承诺总是满足,也就是“等待承诺在继续之前解决”

4 个答案:

答案 0 :(得分:5)

免责声明 - 弄乱你的根范围不是一个好主意。如果你正在阅读这篇文章,请注意OP,@ dalu已经完成了这条路线,并用http拦截器解决了他的问题。仍然 - 回答这个问题非常有趣,所以你可能喜欢自己尝试一下:


可能有点晚了,但是这里有了

正如评论中提到的,根据我迄今为止的经验,这与ui-router的api(v0.2.13)无法实现,因为他们已经声明了真正的根状态,名为""Looks like there's been a pull request in for the past couple years about what you're looking for,但它看起来不像是在任何地方。

根状态的属性如下:

{
    abstract: true,
    name: "",
    url: "^",
    views: null
}

也就是说,如果您想扩展路由器以添加此功能,您可以通过装饰$stateProvider来轻松完成此操作:

$provide.decorator('$state', function($delegate) {
  $delegate.current.resolve = {
    user: ['User', '$stateParams', httpRequest]
  };
  return $delegate
});

请注意,有两个current s:$delegate.current - 原始""州 - 和$delegate.$current - 其包装。

但是,在找到你想要的解决方案之前,我发现了一些障碍。每次导航到新状态时,您都会发出另一个必须在前进之前解决的请求。这意味着此解决方案不比$stateChangeStart上的事件处理好,或者使某些"top"状态更好。我可以想到三个解决方案:

  • 首先,缓存您的http呼叫。除了我可以看到这几乎是如何使某些用例失效,也许你正在做一些会话。
  • 接下来,使用您的一个单件选项(控制器/服务)有条件地进行调用(可能只是为第一次加载设置一个标志)。由于国家被拆除,它的控制器可能也是如此 - 服务可能是你唯一的选择。
  • 最后,请查看其他一些路由方式 - 我没有过多地使用ui.router-extras,但粘性状态深层状态重定向可能会执行此操作特技。

我想,最后,我有义务提醒你要注意你在根级工作的事实。所以,我的意思是,在根级别做任何事情时要小心。

我希望这能回答你的问题!

答案 1 :(得分:5)

从ui-router 1.0.0-beta.3开始,您现在可以使用转换挂钩轻松完成此操作:

angular
  .module('app')
  .run(run);

function run($transitions, userService) {

  // Load user info on first load of the page before showing content.
  $transitions.onStart({}, trans => {

    // userService.load() returns a promise that does the job of getting
    // user info and populating a field with it (you can do whatever you like of course).
    // Just remember to finally return `true`.
    return userService
      .load()
      .then(() => true);
  });
}

在继续加载州之前,州经理将等待承诺解决。

重要提示:确保userService仅加载一次数据,当它已经加载时,它应该只返回已解决的保证。因为上面的回调将在每个状态转换时调用。例如,要处理登录/注销,您可以创建userService.invalidate()并在执行登录/注销后但在执行$state.reload()之前调用它。

答案 2 :(得分:0)

这是不同的方法

将以下代码添加到您应用的.run阻止

// When page is first loaded, it will emit $stateChangeStart on $rootScope
// As per their API Docs, event, toState, toParams, fromState values can be captured
// fromState will be parent for intial load with '' name field
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState){

    // check if root scope
    if(fromState.name == ''){

        // add resolve dependency to root's child
        if(!toState.resolve) toState.resolve = {};
        toState.resolve.rootAuth = ['$_auth', '$q', '$rootScope', function($_auth, $q, $rootScope){


            // from here on, imagine you are inside state that you want to enter
            // make sure you do not reject promise, because then you have to use 
            // $state.go which will again call state from root and you will end up here again
            // and hence it will be non ending infinite loop

            // for this example, I am trying to get user data on page load
            // and store in $rootScope
            var deferred = $q.defer();

            $_auth.user.basic().then(
                function(authData){
                    // store data in rootscope
                    $rootScope.authData = authData;
                    deferred.resolve(authData);
                    console.log($rootScope.authData);
                },
                function(){
                    $rootScope.authData = null;
                    deferred.resolve(null);
                    console.log($rootScope.authData);
                }
            );

            return deferred;
        }];
    }
});

如果您需要刷新状态更改$state.go('name', {}, {reload:true});,请使用authData方法(以便过渡状态始终从root开始,否则解决加载authData永远不会调用一旦root被加载,它永远不需要再次被调用{除了页面重新加载}。)。

答案 3 :(得分:-1)

在状态定义中使用resolve属性。

.state('root', {
    resolve: {
        user: ['$http', function($http) {
            return $http.get('/api/user/status')
        }]
    },
    controller: function($scope, user) {
        $scope.user = user;  // user is resolved at this point.
    }
})

请参阅: