1

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.

4 Answers 4

5

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

Sign up to request clarification or add additional context in comments.

1 Comment

Thumbs up for the explanation dude
2

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

3 Comments

So while I have issues doing it here due to the reasons you said...when it comes to using it in the view it should appear with no problems using an ng-repeat to loop through the array items?
exactly. this is because of how angular two-way data-binding works. As soon as you API call returns and success callback executes, $scope.users is updated. Angular detects this and updates UI via ng-repeat as it has a watch associated with it.
Thanks I'll take a look at implementing it into the view
0

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.

Comments

0

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

1 Comment

Mmmmm perhaps it is my OCD... I like putting them up there. The function part might help though, always works for me. Other than that, it could be an issue in the control.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.