17

Here is my code:

var userRef = new Firebase("https://awesome.firebaseio.com/users/");

var tokenRef = userRef.child(key+'/tokens');
tokenRef.once('value', function(snapshot){

  var userTokenSync = $firebase(tokenRef);
  var userTokens = userTokenSync.$asArray();


  console.log(userTokens);
  console.log(userTokens[0]);
        
  for(var i=0, len = userTokens.length; i < len; i++) {
     console.log(userTokens[i]);
  }
  console.log('done');
})

This code gets the tokens of a user from firebase, and I just want to browse the tokens array.

Here is what the console gives me:

enter image description here

As you can see, I cannot access the array. Do you have any idea of how I could do this?

Thanks in advance.

1

1 Answer 1

23

Welcome to Asynchronous Loading 101.

  var userTokens = userTokenSync.$asArray();

  console.log(userTokens);
  console.log(userTokens[0]);

  for(var i=0, len = userTokens.length; i < len; i++) {
     console.log(userTokens[i]);
  }
  console.log('done');

The first line of this snippets starts loading your data from Firebase. But that loading might take some time. And since the browser doesn't want to block things, it continues executing the script.

By the time the browser executes your console.log(userTokens); the data most likely hasn't been loaded yet. So it just prints the object to the console as a placeholder.

By the time it gets to the for loop, the data may or may not yet have been loaded from Firebase.

At some point you clicked the arrow next to the logged userTokens. By that time the data had loaded from Firebase and the console shows the latest data.

The solution is provided by AngularFire, in the form of a promise. AngularFire promises to at some point in the future have the data for you. If you have a piece of code that should only execute when the data is loaded, you can write it like this:

  var userTokens = userTokenSync.$asArray();

  console.log(userTokens);
  console.log(userTokens[0]);

  userTokens.$loaded(function(userTokens) {
    for(var i=0, len = userTokens.length; i < len; i++) {
      console.log(userTokens[i]);
    }
    console.log('done');
  });

  console.log('at last line, but not done yet');

Update

Note that the above is a bad example of when to use $loaded. Since $loaded will fire only once, it will only log the initial contents of the array. If you're just trying to see if/when your data has loaded, the idiomatic approach is to add the userTokens to the scope:

$scope.userTokens = userTokens;

And add this to your view/HTML:

<pre>{{ userTokens | json }}</pre>

AngularFire will now monitor when the userTokens are loaded or modified in any way and will tell AngularJS to update the view if that happens.

Also see these:

Yup... we get this question a lot.

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

3 Comments

I'd call that authoritative.
@Frank Thanks so much for this and the many other answers you've written. You are being extremely helpful.
You're welcome Kyle. It's nice to be appreciated (in more than just upvotes). But it's also just plain fun to help people use and understand the many cool technologies out there.

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.