Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asynchronous access to an array in Firebase

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.

like image 348
Vico Avatar asked Nov 20 '14 20:11

Vico


1 Answers

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:

  • Firebase, AngularJS and GeoFire - wait for response from factory
  • Firebase angularfire child.$asObject give properties undefined
  • angularfire - why can't I loop over array returned by $asArray?
  • Passing variable in parent scope to callback function
  • Trying to get child records from Firebase

Yup... we get this question a lot.

like image 190
Frank van Puffelen Avatar answered Oct 06 '22 18:10

Frank van Puffelen