dermoritz
dermoritz

Reputation: 13001

AngularJs defined global variable, service' content is null

I am writing my first AngularJs app. The app needs to know the current user in different controllers. The current user is retrieved through a rest call. First i just added current user information on top of the page using $scope:

var currentUser = {};
app.controller('currentUserCtrl', function($scope, $http) {
    $scope.currentUser = null;
    $http.get(rootUrl + '/timetracker/user/current').success(
            function(response) {
                $scope.currentUser = response;
                currentUser = response;
            });
}

);

The controller works fine but "currentUser" can't be accessed by other controllers. My 2nd try (after reading about global variables) was to use $rootScope. So i changed the above $rootScope.currentUser = response; and omitted the var currentUser. I added $rootScope to all my controllers an tried to get currentUser.id. But this didn't work neither - the user object is null. My third try was to use a factory:

app.factory('currentUser', function($http){
    var currentUser = {};
    $http.get(rootUrl + '/timetracker/user/current').success(
            function(response) {
                currentUser = response;
            });
    return currentUser;
});

My controllers now inject "currentUser" but this is also null (all values i want to get are "undefined"). So how to make current user globally available?

Could it be that the currentUser is used before the async call and write of variable is successful? How to be sure that currentUser call is finished?

EDIT controller that uses currentUser:

app.controller('createBookingCtrl', function($scope, $http, $filter, currentUser) {
    //list of projects for current user (usersprojects)
    $scope.projectsList = {};
    $http.get(rootUrl + '/timetracker/usersprojects/user/' + currentUser.id).success(function(response) {
        for (var i = 0; i < response.length; ++i)
            //map users project by projects name
            $scope.projectsList[response[i].project.name] = response[i];
    });
});

currentUser.id has value undefined.

2nd EDIT I just tested with js debugger: the in factory currentUser = response runs after the other controller access to the value. So how to be sure/ wait for response?

Upvotes: 4

Views: 601

Answers (1)

GuilloOme
GuilloOme

Reputation: 311

In aSync context (like javascript), it's all about promises.

My guess would be to place the responsibility of manipulating/feeding the currentUser in a service/factory. And all your controller will ask for the currentUser there. This way you be sure to always get a valid version of your currentUser. The problem is to know when this currentUser Object is ready, that's why you need to use promise object that will tell you when to act.

Let say you have a CurrentUserService with a getCurrentUser method, this method will return a promise object:

app.service('CurrentUserService', function($http) {
  var currentUser,
      urlToCurrentUser = 'http://example.com/currentUserAPI';

  function getCurrentUser() {
    return $http.get(urlToCurrentUser).success(
      function(response) {

        currentUser = response;

        return currentUser;
      });
  }

  return {
    getCurrentUser: getCurrentUser
  };
});

Now, let's see how will behave the controller which need this currentUser.

First, the controller need to access our CurrentUserService. Then, it will just call the getCurrentUser on the service.

app.controller('SomeControllerController', function(CurrentUserService) {
  var currentUserInTheController;

  ...
  CurrentUserService.getCurrentUser().then(function(currentUser){
       currentUserInTheController = currentUser;
       // from here and only in the current function, currentUserInTheController is defined for sure !
  });
  ...
});

The key here is the .then() method. This method will be called only once the $http is resolved (and so the promise). So it is important to understand that if you try to access currentUserInTheController before this "resolve", it will be undefined.

To be certain to have a currentUserInTheController not undefined, you need to do every action on it in the callBack function in the .then() (see the comment in the code)

The science of the promise mechanism is crucial to understand in javascript ;)

Read more : http://andyshora.com/promises-angularjs-explained-as-cartoon.html and AngularJS : Where to use promises?

Upvotes: 0

Related Questions