germainelol
germainelol

Reputation: 3331

AngularJS - $scope variable not storing the data outside of the function

I've got a pretty simple function like this inside my controller:

fetchUsers = function () {
  UserService.getUsers().
  success(function(data, status) {
    $scope.users = data.users;
    console.log($scope.users);
  });
};

fetchUsers();

console.log($scope.users);

It's basically using a service to retrieve some data from an API, and the console.log inside of the function is working fine and sends an array to console of [Object Object] which I can open up and see all my users no problem. However, when I then put this outside of the function by calling fetchUsers() and running a console.log I simply get an empty array returned where [] is output to the console.

Can anyone think of anything that would cause this? I'm a bit baffled by it.

Upvotes: 1

Views: 887

Answers (4)

omikes
omikes

Reputation: 8513

Make $scope.users global by initializing it outside of the function perhaps? I also threw the function inside the getUsers method:

$scope.users = [];

fetchUsers = function () {
  UserService.getUsers(function(data, status) {
    $scope.users = data.users;
    console.log($scope.users);
  })
};

fetchUsers();
console.log($scope.users);

Upvotes: 0

adrian_reimer
adrian_reimer

Reputation: 469

Your code is running properly. It is the asynchronous nature of the request that is causing the confusion. Because its asynchronous, the success callback is actually executed last, after your 2nd console.log() call.

Upvotes: 0

kachhalimbu
kachhalimbu

Reputation: 2200

UserService.getUsers() is returning a promise which will resolve in future as it is executed in async with your controller code so your console.log($scope.users) in your controller is most likely being executed before the API call returns and success callback is executed.

Put a breakpoint in browser developer tools on both console.log() statement and you should observe this behavior.

Here is a pretty simple explanation of promises in general

Upvotes: 2

yangli-io
yangli-io

Reputation: 17334

Ahh I see you've finally been hit by asynchronous code of javascript. Not everything runs in order.

For example if I have this piece of code

setTimeout(function(){
    var test = 'hello';
    console.log('first test : ' + test);
}, 1000)

console.log('second test : ' + test);

You'll notice that the second test will return nothing even though test is set earlier (in terms of line number). Now you may think, so what you set it to 1000 milli-seconds (but try the same code and set it to 0 seconds, you will see the same effect. This is due to the event loop which is used to manage asynchronous code - basically whatever is in your setTimeout is placed at the end of the priority, which means when the second console log is called - test is not defined yet.

Why asynchronous you ask? The thing with browsers is UI and javascript is run on the same thread, so imagine if the setTimeout got stuck there and waited for 1 whole second, nothing in your UI would work - it would freeze.

With that said, another important usage of asynchronous code is http requests to a server. These requests can take a variant of time which means if you use synchronous code, your UI would freeze up. Imagine facebook - which is constantly retrieving data from its servers.

Going back to your code, this method below retrieves data from the server

UserService.getUsers().
  success(function(data, status) {
    $scope.users = data.users;
    console.log($scope.users);
  });

The stuff inside the success function is again asynchronous, so whatever you put after that will run straight away and whatever is inside the success function will run once your 'promise' or request has been fulfilled.

Hence you might have

fetchUsers();

console.log($scope.users);

But note that $scope.users is set after this console.log

Upvotes: 5

Related Questions