Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ensuring one AngularJS controller loads before another

I'll preface this with the fact that I really have no idea if this is the best way to achieve what I'm doing and I'm very open to better suggestions.

I've got a user account system using OAUTH2 which gets looks up user info in my database and saves it as a variable, $rootScope.userInfo. This resides in a controller which is appended to my app's body; here I was thinking that the highest-level controller would load before those that live within it, but apparently not.

If I load a view which tries to access this $rootScope.userInfo object before my mainCtrl has had a chance to load it in from my database, it throws a javascript error and Angular breaks.

For reference, here's a rough idea of the template:

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

I'm loading $rootScope.userInfo in mainCtrl like this:

$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';
    });

Then for my userProfile control, I do:

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);
  }
}

If I'm coming from a different page in the app which doesn't call on $rootScope.userInfo, the API has enough time to look it up and my userProfile page works fine. However if doing a full-page refresh, the $rootScope.userInfo doesn't have time to load and I get errors.

How can I fix this?

like image 815
JVG Avatar asked Aug 22 '13 07:08

JVG


1 Answers

The problem you describe is one of the reasons why it is not recommended to share data between controllers using $rootScope: it creates a manual "invisible" dependency between two controllers, that you have to manually fix when the end user hasn't gone through the other controller yet.

The recommended solution is to move the user loading logic into a service, say userProfileService, which you inject into both controllers that need it. It will then be created once, and used for both controllers. In such a service you could load the user profile with $http when a controller asks for it, and return it from cache when the next one does. This way, the dependency goes from both controllers to a shared service, rather than from one controller to another.

I'm not a huge fan of the AngularJS documentation, but these might help: DI, Creating Services, and Injecting Services.

like image 95
Steve Klösters Avatar answered Nov 03 '22 02:11

Steve Klösters