确保一个AngularJS控制器先于另一个加载

Ensuring one AngularJS controller loads before another

本文关键字:控制器 另一个 加载 AngularJS 一个 确保      更新时间:2023-09-26

在开始这篇文章之前,我真的不知道这是否是实现我正在做的事情的最佳方式,我非常愿意接受更好的建议。

我有一个使用OAUTH2的用户帐户系统,它可以在我的数据库中查找用户信息,并将其保存为变量$rootScope.userInfo。这驻留在一个控制器中,该控制器附加到我的应用程序的body;在这里,我认为最高级别的控制器会在其中的控制器之前加载,但显然不是。

如果我在mainCtrl有机会从数据库加载之前加载了一个试图访问此$rootScope.userInfo对象的视图,它会抛出一个javascript错误,Angular会中断。

作为参考,这里有一个模板的大致想法:

<body ng-controller="mainCtrl">
    <header>Content</header>
    <div class='main-view' ng-controller="userProfile">
        <p>{{user.name}}</p>
        <p>{{user.email}}</p>
    </div>
</body>

我正在mainCtrl中加载$rootScope.userInfo,如下所示:

$http.get('/api/users/' + $cookies.id).
    success(function(data) {
      $rootScope.userInfo = data.user[0];
      console.log("User info is:");
      console.log($rootScope.userInfo);
      $scope.status = 'ready';
    });

然后,对于我的userProfile控制,我会:

function userProfile($scope, $cookies, $http, $routeParams, $rootScope){
  if($scope.status == 'ready'){
    $scope.user = $rootScope.userInfo;
    console.log("Double checking user info, here it is:");
    console.log($rootScope.userInfo);
  }
}

如果我来自应用程序中不调用$rootScope.userInfo的其他页面,API有足够的时间查找它,我的userProfile页面工作正常。但是,如果进行全页刷新,$rootScope.userInfo就没有时间加载,并且会出现错误。

我该怎么解决这个问题?

您描述的问题是不建议使用$rootScope在控制器之间共享数据的原因之一:它在两个控制器之间创建了手动的"不可见"依赖关系,当最终用户还没有通过另一个控制器时,您必须手动修复该依赖关系。

建议的解决方案是将用户加载逻辑移动到一个服务中,比如userProfileService,将其注入到两个需要它的控制器中。然后,它将被创建一次,并用于两个控制器。在这样的服务中,当控制器请求时,您可以用$http加载用户配置文件,并在下一个请求时从缓存中返回。通过这种方式,依赖关系从两个控制器转移到共享服务,而不是从一个控制器转移至另一个控制器。

我不是AngularJS文档的超级粉丝,但这些文档可能会有所帮助:DI、创建服务和注入服务。

使用then而不是成功,并使用ng-include:延迟加载子控制器

<body ng-controller="mainCtrl">
    <header>Content</header>
    <ng-include src="templatePath"></ng-include>        
</body>

在新模板userprofile.html:中移动HTML

<div class='main-view' ng-controller="userProfile">
    <p>{{user.name}}</p>
    <p>{{user.email}}</p>
</div>

主目录中的回调Ctrl:

$http.get('/api/users/' + $cookies.id).
    then(function(data) {
        /* mainCtrl being the parent controller, simply exposing the 
           properties to $scope would make them available 
           to all the child controllers.*/
        $rootScope.userInfo = data.user[0];
        /* assign the template path to load the template and 
           instantiate the controller */
        $scope.templatePath = "userprofile.html";
    });