本文介绍了使用服务和控制器控制操作顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两项服务 - 一项用于存储用户详细信息,另一项用于调用以检索这些详细信息:

I have two services - one to store user details and the other to make a call to retrieve those details:

userService 存储要在整个应用中使用的用户详细信息(即注入控制器、服务等)

function userService($log) {
    var id = '';
    var username = '';
    var isAuthenticated = false;

    var service = {
        id: id,
        username: username,
        isAuthenticated: isAuthenticated
    };

    return service;
}

authService 用于(希望只有一次)从 Web API 控制器检索用户详细信息:

function authService($log, $http, userService) {
    $log.info(serviceId + ': Inside authService method');

    var service = {
        getUserDetails: getUserDetails
    };

    return service;

    function getUserDetails() {
        $log.info(serviceId + ': Inside getUserDetails method');

        return $http.get('api/authentication', { cache: true });
    }
}

最初,我在 .run 块中调用了 authService fire,如下所示:

Initially, I had the call to the authService fire in a .run block like so:

.run(['$log', 'authService', 'userService', function ($log, authService, userService) {

    authService.getUserDetails()
        .then(querySucceeded);

    function querySucceeded(result) {
        userService.id = result.data.Id;
        userService.username = result.data.username;
    }
}]);

但问题是 getUserDetails 返回的承诺直到我的控制器触发后才解决,因此对我来说为时已晚.用户数据未准备好.

But the problem was that the getUserDetails-returned promise did not resolve until after I my controllers fired and, thus, too late for me. The user data was not ready.

然后我查看了 $stateProvider 中的 resolve 选项(用于 UI-Router):

I then looked at the resolve option in the $stateProvider (for UI-Router):

.state('dashboard', {
                url: '/dashboard',
                views: {
                    header: {
                        templateUrl: 'app/partials/dashboard/header.template.html',
                        controller: 'DashboardHeaderController',
                        controllerAs: 'dashboardHeaderVM',
                        resolve: {
                            user: function (authService) {
                                return authService.getUserDetails();
                            }
                        }
                    }
                }
            })

假设在 resolve 部分中的 promise 被解决之前,视图不会被呈现.这似乎工作正常.

The assumption is that the view won't be rendered until the promise in the resolve section is, well, resolved. That seems to work fine.

这是我使用返回的用户属性的(相关部分)控制器:

Here's the (relevant part of the) controller where I use the returned user property:

function DashboardHeaderController($log, user) {
    var vm = this;

    // Bindable members
    vm.firstName = user.data.firstName;
}

但是,我有两条路线(更多路线),用户可以导航到任一路线.我是否需要在 authService 的每个状态部分都有一个解析属性?我想调用 authService.getUserDetails 一次,无论提供哪个路由,然后让它可用于任何路由、控制器等.

However, I have two routes (more to come) and a user can navigate to either one. Do I need to have a resolve property in each state section for the authService? I want to fire the call to authService.getUserDetails just once no matter which route is served and have it available after that for any route, controller, etc.

有没有更好的(最佳实践)方法来做到这一点?

Is there a better (best practice) way to do this?

推荐答案

不确定更好或最佳实践,但这里有一个 plunker 以我的方式.

Not sure about better or best practice, but here is a plunker with my way.

重点是将resolve 移动到某个 根状态.应用程序中所有状态的祖先:

The point is to move resolve into some parent root state. The one who is ancestor of all states in the application:

$stateProvider
  .state('root', {
    abstract : true,
    // see controller def below
    controller : 'RootCtrl',
    // this is template, discussed below - very important
    template: '<div ui-view></div>',
    // resolve used only once, but for available for all child states
    resolve: {
      user: function (authService) {
          return authService.getUserDetails();
      }
    }
  })

这是具有resolve的根状态.唯一有决心的国家.这是它的第一个孩子的示例(任何其他孩子都将以类似方式定义:

This is a root state with resolve. The only state with resolve. Here is an example of its first child (any other would be defined similar way:

$stateProvider
    .state('index', {
        url: '/',
        parent : 'root',
        ...

这种方法开箱即用.我只想提一下,如果 'RootCtrl' 是这样定义的:

This approach will work out of the box. I just would like to mention that if the 'RootCtrl' is defined like this:

.controller('RootCtrl', function($scope,user){
  $scope.user = user;
})

我们应该了解 UI-Router 继承.见:

we should understand the UI-Router inheritance. See:

小引用:

请记住,如果您的状态的视图是嵌套的,那么范围属性只会沿状态链向下继承.范围的继承属性状态的嵌套一切无关视图的嵌套(模板).

您完全有可能拥有嵌套状态,其模板在您站点内的各种非嵌套位置填充 ui-view.在这种情况下,您不能期望在子状态的视图中访问父状态视图的范围变量...

It is entirely possible that you have nested states whose templates populate ui-views at various non-nested locations within your site. In this scenario you cannot expect to access the scope variables of parent state views within the views of children states...

更多解释可以在这个Q &一个

那么,这是什么意思?

我们的根视图只能将 resolved 内容传递到子状态 - 如果它们的视图是嵌套的.

例如,$scope.user 只会在子状态/视图/$scopes 像这样嵌套时才会被继承

For example, the $scope.user will be inherited in child states/views/$scopes only if they are nested like this

.state('index', {
    url: '/',
    parent : 'root',
    views: {
      '' : { // the root view and its scope is now the ancestor
             // so $scope.user is available in every child view
        templateUrl: 'layout.html',
        controller: 'IndexCtrl'
      },
      'top@index' : { templateUrl: 'tpl.top.html',},
      'left@index' : { templateUrl: 'tpl.left.html',},
      'main@index' : { templateUrl: 'tpl.main.html',},
    },

这里

这篇关于使用服务和控制器控制操作顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-16 03:59
查看更多