Trying to get child records from Firebase - angularjs

Am in the angular-fire-seed tutorial stage and experimenting with messages and child posts, for some bizarre reason I cannot see the children when I explicitly try to display them, but can see it when expanding on the parent node in the console. These messages display properly in the html where I have the ng-repeat, so I know I am getting the messages at least, albeit childless.
I thought angularfire-seed utils might be chopping or slicing some children so I reverted to straight firebase
This is what I have:
Code:
-----
var url = fbutil.ref() + "/messages/";
var ref = new Firebase(url);
var sync = $firebase(ref).$asArray();
console.log(sync); //this I can see as a proper $firebaseArray object
console.log(sync.length); //this displays as 0 even though length is 3 in object above
console.log(sync[1]); //displays as undefined
Data:
----
messages/id1/text
/id2/text
/id2/post
/id3/text
Thanks in advance for pointing out what I am mis-assuming !

You seem to be falling for the common asynchonisity problem.
This is your code fragment:
var sync = $firebase(ref).$asArray();
console.log(sync); //this I can see as a proper $firebaseArray object
console.log(sync.length); //this displays as 0 even though length is 3 in object above
console.log(sync[1]); //displays as undefined
The call to $asArray() doesn't return a Firebase array immediately, since the data may take some time to come down from the Firebase servers. So instead it returns the promise of a Firebase array, something that in the future will contain your data.
By the time you inspect the out of console.log(sync) in the console, the data will have downloaded so it is (as you say) a proper synchronized array. But when the console.log(sync.length) line runs, the data probably hasn't downloaded yet.
You can wait for the data to be downloaded with the $loaded() method. So:
var sync = $firebase(ref).$asArray();
console.log(sync);
sync.$loaded().then(function(sync) {
console.log(sync.length);
console.log(sync[1]);
}

got the answer from AngularFire Accessing child element methods
short answer: once assigned to a JS var, it is a POJO, not a $firebase object anymore.

Related

AngularFire - Get a firebaseObject for each item in a firebaseArray ng-repeat

I have an ng-repeat which is connected to a firebaseArray which is an index of a user's doc Ids.
I want to display a list of their docs with additional info for each one, e.g. it's title and description.
My firebase structure is:
+users
- userId1
-theirDocs
-docId1: true
-docId2: true
+docs
-docId1
- tile
- description
- url
-docId2
- etc etc
I've tried everything and still can't get this to work, it seems a pretty common use case. I've tried using a function that calls a firebaseObject each time. I've tried using a separate controller. I've tried a directive, I've even tried using firebase.utils library (I think out of date now).
Can anyone recommend the best way to do this using AngularFire? Thanks in advance!
It would be better to see a code snippet as to fully understand what you've tried first of all, as it's difficult to determine where the issues lie. That being said, as long as your rules are not preventing this, you may need to wait for the data to download using $loaded function beforehand.
EXAMPLE
This example is clearly available by following this link, yet here is an example for further clarity:
var yourFirebaseReference = firebase.database().ref("REPLACE WITH YOUR FIREBASE BRANCH HERE");
var data = $firebaseArray(yourFirebaseReference);
data.$loaded().then(function(x) {
console.log(data) // Example, you can do what you want with your 'data' now as the data has loaded
x === data; // true
}).catch(function(error) {
console.log("Error:", error);
});

angular resource clears object data after post

my angular app clears data after post.
Here is the snippet from controller:
$scope.saveDevice = function() {
var deviceId = $scope.device.id;
if (deviceId) {
$scope.device.$update(function(result) {
$location.path('/devices');
});
} else {
$scope.device.$save().then(function (deviceResult) {
$scope.device.id = deviceResult.deviceId;
$scope.device.$activationCode(function (result) {
$scope.device.activationCode = result.activationCode;
});
});
}
};
When I hit break point at
"$scope.device.$save().then(function (deviceResult) {" the application shows that device is populated with properties from form. But after the post, device is cleared of any properties. Is this normal behaviour? If so, how can I prevent it?
Here I found the answer to my problem:
AngularJS - Prevent Form Clear
Basically:
call class method
Device.save($scope.device) //....
instead of
$scope.device.$save
and it will presist the data you've in $scope.device class.
I'm not sure if this helps, but from the docs. This is too long to put as a comment.
Angular Doc
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data. This means that in most cases one never has to write a callback function for the action methods.

angularfire - why can't I loop over array returned by $asArray?

I'm using AngularFire 0.8
I called the following function to get an instance of an array.
var test = $firebase(new Firebase(URL)).$asArray();
When I console.log 'test', I get the following (see screenshot).
It looks like test is an array. However, when I do "console.log(test[0])", I get undefined.
Why isn't test an array with two elements like console.log(test) seems to show it should be???
Help!!
Most likely you're calling console.log on the array before the data is loaded.
To access the data in the array, you have to wait until the data is loaded.
To do that in code, you use this construct:
var test = $firebase(new Firebase(URL)).$asArray();
test.$loaded().then(function(array) {
console.log(array[0]);
});
Update
This answer gets more upvotes than I think it's worth. When you're using AngularJS and AngularFire, it is often a bad omen when you use console.log to debug the data that is loaded.
The AngularFire documentation on handling asynchronous operations now has to say on it:
The easiest way to log the data is to print it within the view using Angular's json filter.
{{ data | json }}
AngularFire tells the Angular compiler when it has finished loading the data, so there is no need to worry about when it be available.

Render an object's children from Firebase in AngularJS

I'm following the "denormalized" data pattern that #Anant described nicely on the Firebase blog. To query and render child objects he suggests listening for child_added events on the parent to get the child ids, then querying those children individually with .once('value', fnc) to render them. From the blog post (he uses a posted Link as the parent and Comments as children -- think Reddit or Hacker News):
var commentsRef =
new Firebase("https://awesome.firebaseio-demo.com/comments");
var linkRef =
new Firebase("https://awesome.firebaseio-demo.com/links");
var linkCommentsRef = linkRef.child(LINK_ID);
linkCommentsRef.on("child_added", function(snap) {
commentsRef.child(snap.name()).once("value", function() {
// Render the comment on the link page.
));
});
[sic]
I'm trying to reconcile this with my AngularJS view, since adding the result of .once into a $scope array and using ngRepeat will leave you with a static list (the children won't update in realtime if they are changed or removed by another client).
Put another way, I'd like to have something like an angularFireCollection of child objects that will add, remove and update dynamically.
I think what you're looking for is a combination of AngularFire and FirebaseIndex. I haven't checked that combining these still works, but Kato reports it has in the past.
Ignoring that for a second, though, I don't see anything wrong with your proposed plan:
push the result of .once into an array, add it to the $scope and use ngRepeat
In this case, Kato's FirebaseIndex will probably still be useful, so definitely check that out.

How to clear a model when my AngularFire app loads initially?

I am new to AngularFire and am trying to understand a simple concept. If you go through the AngularFire tutorial located at the following url: http://angularfire.com/tutorial/index.html#gettingstarted there is a rudimentary example of using AngularFire to build a primitive "chat" application.
The tutorial is very clear and concise but I do not understand one primary point with it:
function MyCtrl($scope, angularFire){
$scope.messages = [];
var ref = new Firebase("https://<xxxxxx>.firebaseio.com/messages");
angularFire(ref, $scope, 'messages');
$scope.messages = []; //shouldn't this clear the data locally and remotely?
}
The issue is that a model is first created, and then the binding magic with AngularFire is setup such that there is now a 3-way binding to the model. If there is an array of data already stored in Firebase, that data is fetched and synced and your model will now have this data locally.
What I simply do not understand is, when the controller code runs, suppose I set the model to an empty array AFTER the angularFire binding is wired up, why doesn't the Firebase data get cleared out? Never mind the fact, that refreshing the page would basically keep wiping out the data (the behavior I want).
Now, I can get this behavior to work, if I wire up an ng-click event to a button, that calls a method named clear defined on my $scope object. If within, that method, I simply call: $scope.messages = [];, then my model is cleared locally, and remotely.
But why doesn't this work on initialization?
Help is always appreciated.
I think I may have found an answer to my own problem. It looks like, you must wait until the promise returns to actually start modifying the model like so. Now whenever I refresh my page, when my .then() runs, it will clear out my data.
I suppose this is how it should be done. Can anyone confirm?
$scope.messages = [];
var ref = new Firebase("https://<xxxxxx>.firebaseio.com/items");
var prom = angularFire(ref, $scope, 'messages');
prom.then(function(){
console.log("data loaded");
$scope.messages = [];
});
I'm guessing the remote data hasn't returned yet and is populated after your second call to $scope.messages =[]
edit:
Why not just explicitly remove your data from FB before binding it to a local list.
var ref = new Firebase("https://<xxxxxx>.firebaseio.com/messages");
ref.remove();

Resources