-1

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?

Sean
  • 1,151
  • 3
  • 15
  • 37
  • This code does not reproduce the problem. As such ii is not useful to other readers. Please edit the question to include a [Minimal Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). – georgeawg Feb 20 '20 at 03:55

3 Answers3

1

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?

Konstantin A. Magg
  • 1,106
  • 9
  • 19
  • Just gave it a go and it still doesn't work. In fact, there is one place in the same controller where I use the $rootScope.userLoggedIn variable in the view and that too doesn't work (just saw that). What is really strange is when I open up the debug console in the browser, it works! What is going on here? Certainly seems like an async issue... – Sean Feb 19 '20 at 13:12
  • From what I understood now, I would check if your view finds the correct scope. That was quit a pain in Angular.js. I'll paste some code snippets above... – Konstantin A. Magg Feb 19 '20 at 13:16
  • Thanks. I added that in like you said and it just shows as false. When I don't initialise it, it doesn't show up meaning the variable doesn't exist yet so seems like a timing issue. I thought Angular took care of that by design? Any suggestions? – Sean Feb 19 '20 at 13:31
  • Remembering the good old Angular.js ;) I would try to avoid the $scope completely and attach the variable to your controller: Controller `self.userLoggedIn = true` and Template: `ng-show="$ctrl.userLoggedIn"`). – Konstantin A. Magg Feb 19 '20 at 13:59
  • I do need it under $rootScope though as I need it that variable in other controllers BUT I did give it a go to at least see if it will work. You won't believe it, it didn't. $ctrl.userLoggedIn is now not even showing up when I save it as self.userLoggedIn = true – Sean Feb 19 '20 at 14:14
  • Manually saved it as true just to check for obvious faults and it does work. So it's just a timing issue. Just can't crack this one. – Sean Feb 19 '20 at 14:15
1

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>
Community
  • 1
  • 1
georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • Yes and thanks but you added a delay. That defeats the whole purpose I'm afraid. – Sean Feb 20 '20 at 03:48
  • The delay simulates the delay that an HTTP request would take before setting the $rootScope variable. This code demonstrates that variables in $rootScope set asynchronously will show in the template of all controllers, not just the controller that receives the XHR. – georgeawg Feb 20 '20 at 03:54
  • Thanks mate but it did not work for me. I know it is supposed to work but it didn't. I finally found the solution......updated Angular from 1.6.4 to 1.7.9. That did it. Very frustrating when the answer was so obvious and I missed it entirely. – Sean Feb 22 '20 at 07:30
0

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

Sean
  • 1,151
  • 3
  • 15
  • 37