Async variable stored in $rootScope not available in other controllers

288 Views Asked by At

I am using Angular 1.x for my stack and when I make an API call and store the response in the $rootScope, it is not accessible in other controllers' view.

My controller:

angularApp.controller('mainController', ['$scope', '$rootScope', '$http', function($scope, $rootScope, $http){

  var checkIfAuthenticated = function(){
    return $http.get('/api/isAuthenticated');
  };

  checkIfAuthenticated()
  .then(function(res) {
    if(res.status===200){
        console.log("Success");
        $rootScope.userLoggedIn = true;
    } 
  })
}]);

Now, in another controller's view I use it like this:

<div ng-if="userLoggedIn" class="py-1 pl-1 pr-1">
  <span><b>Message Board</b></span>
  <div class="form-control" readonly id="lockTextbox">Show something</div>
</div>

The problem is, the API call /api/isAuthenticated does provide the right response (status 200) but the ng-view gets it wrong.

I am sure this is to do with $rootScope.userLoggedIn being a response from an async call (as I get Success in my console) but how do I solve it?

Thanks in advance!

EDIT

After I posted the question, I noticed that in the mainController's view, the ng-if logic doesn't work either. What is very strange is that when I open up the browser's debug console, it starts working! I think this is just an async issue but I don't know how to solve it. How do I tell the view that the variable is on it's way?

3

There are 3 best solutions below

0
Sean On BEST ANSWER

I found the problem. I updated my Angular from 1.6.4 to 1.7.9 (and all modules like angular-sanitize etc) and that did the trick. Should have been the first thing I did but I missed it entirely

6
Konstantin A. Magg On

OK, to solve the timing issue, I'll rework the answer completely. This should be a - quick and dirty but - working example:

index.html

<html>
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
    <script src="script.js"></script>
  </head>

  <body ng-app="plunker" ng-cloak>
    <div ng-controller="MainCtrl as $ctrl">
      <h1>Hello {{$ctrl.name}}</h1>
      <p>Start editing and see your changes reflected here!</p>
      <div ng-if="$ctrl.name === 'Angular.js'"><b>Message Board</b</div>
    </div>
  </body>
</html>

script.js

import angular from 'angular';

angular.module('plunker', []).controller('MainCtrl', function($scope, $http) {
  const self = this;
  self.name = 'Plunker';
  console.log('hello');

  function checkIfAuthenticated(){
    console.log('get');
   return $http.get('https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js');
  };

  checkIfAuthenticated().then(function(res) {
    if(res.status===200){
        console.log('Success');
        self.name = 'Angular.js'; // insert any logic here
    } else {
      console.log('Failed');
    }
  })
});

Console

hello 
get 
Success 

Does it work for you?

3
georgeawg On

Working Example

The below demo shows the $rootScope variable available in both controllers after being set from a promise delayed by two seconds.

angular.module("app",[])
.controller('mainController', function($scope, $rootScope, $timeout) {
  var checkIfAuthenticated = function(){
    return $timeout(function() {
        return { status: 200 };
    }, 2000);
  };
  checkIfAuthenticated()
  .then(function(res) {
    if(res.status===200){
        console.log("Success");
        $rootScope.userLoggedIn = true;
    } 
  })
})
.controller('otherController', function($scope) {
  console.log("other controller");
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
  <fieldset ng-controller="mainController">
     MAIN Controller userLoggedIn={{userLoggedIn}}<br>
     <div ng-if="userLoggedIn">
        Message Board - Show something
     </div>
  </fieldset>
  <fieldset ng-controller="otherController">
     OTHER Controller userLoggedIn={{userLoggedIn}}
     <div ng-if="userLoggedIn">
        Message Board - Show something
     </div>
  </fieldset>
</body>