0

Just started learning angular, but i've been making a website with jQuery and am now starting on some apps which hook up to the same firebase as the website.

The problem I have is that I can't find a way to get a child property and use it in a ref. I am wanting to get the value "example" in the sample below:

users: {
    simplelogin:1 {
        CurrentGroup : "example"
     }
  }

What I would normally do with jQuery would be something like:

currentUserRef.on('value', function(snapshot){
    currentGroup = snapshot.val().CurrentGroup;
});

var checkCurrentGroup = setInterval (function(){
    if ( currentGroup !== undefined ) {
        clearInterval(checkCurrentGroup);
        var currentGroupUsersRef = new Firebase(FB + "/groupUsers/" + currentGroup);
        //Rest of the code for the page/app
 }}, 200);

So, how is this done in Angular? My attempt was to copy the example on the firebase guide:

app.factory("Profile", ["$firebase", function($firebase) {
  return function(username) {
    var userRef = new Firebase(FB + "/users/" + username);
    return $firebase(userRef).$asObject();
  }
}]);


app.controller("ProfileCtrl", ["$scope", "Profile",
  function($scope, Profile) {
        console.log("profile = ", Profile(uid));
        console.log("profile current group = ", Profile(uid).CurrentGroup);
      }
]);

console logs:

profile = d {$$conf: Object, $id: "simplelogin:76", $priority: null, $save: function, $remove: function…}$$conf: Object$id: "simplelogin:76"$priority: nullCurrentGroup: "Big Group"displayName: "Jim"email: "someone@email.com"firstLogin: trueprovider: "password"provider_id: "simplelogin:76"proto: Object

profile current group = undefined

I could select the user object but when I did user.currentGroup it would be undefined. No idea if i'm on the right track with that.

Community
  • 1
  • 1
Marty.H
  • 1,194
  • 4
  • 16
  • 29
  • "when I did user.currentGroup it would be undefined" Can you edit your question so that it also includes the code that does this (and thus triggers the error)? – Frank van Puffelen Feb 01 '15 at 13:50
  • Sorry, was a bit silly of me not to put that in. Added it now. – Marty.H Feb 01 '15 at 19:42
  • I'll write up a quick answer below, but in the meantime already read: http://stackoverflow.com/questions/27049342/asynchronous-access-to-an-array-in-firebase/27050749#27050749 – Frank van Puffelen Feb 01 '15 at 19:51

1 Answers1

3

AngularFire's $asObject() returns a $FirebaseObject, which your service in turn returns. I just noticed that the API documentation for $asObject() states:

Returns a synchronized object. When data is updated on the server, the local copy will be altered (but not replaced) to match.

Unfortunately this is not really true (or at best: easy to misunderstand).

Firebase loads (and synchronizes) data from the server to your client code asynchronously. Since it might take quite some time for the data (or updated data) to come back, AngularFire's $asObject() instead returns a so-called promise: a data structure that at some point in the future will contain the data you requested. And clearly by the time you are accessing Profile(uid).CurrentGroup, the data has not yet been downloaded.

Much of this is not a problem when you simply bind the objects to a view, like is normal in AngularJS. If you do that, AngularFire will automatically notify AngularJS when new (or updated) data is available and AngularJS will then update the view. Magic!

But your console.log statement is not part of this magic. And for that reason you will need to handle the promise yourself. Luckily this is not very difficult and very common; so common that the "unintuitive at best" API documentation I quoted above, contains this example of how to do it:

var record = sync.$asObject();
record.$loaded().then(function() {
  console.log("record ID:", record.$id);
});

You should be able to modify this snippet pretty easily for your data. But keep in mind: you won't need $loaded() handlers normally, when you're simply binding the objects to an AngularJS view. AngularFire's three-way data binding should work automatically in that case.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807