Angularfire: How do I iterate through FirebaseListObservable<[]> object

Created on 15 Nov 2016  路  14Comments  路  Source: angular/angularfire

Version info

Angular: 2.1.0

Firebase: 3

AngularFire: 2.0.0-beta.6

Other (e.g. Ionic/Cordova, Node, browser, operating system): Ionic

How to reproduce these conditions

Steps to set up and reproduce

Say I subscribe to a list of items:

this.items = this.af.database.list('items');

And I add to these items in another function:

this.items.push({ im: 'cool' });

Then in another function I'd like to iterate through my items:

this.items.forEach(item => {
    console.log('Item:', item);
});

Expected behavior

I expect console.log(item) to print out $ Item: { im: 'cool' } but instead it prints out an array for each time I added to the items list.

Actual behavior

The whole array is printed multiple times:

$ Item: []
$ Item: [{ im: 'cool' }]
$ Item: [{ im: 'cool' }, { again: 'yep' }]

Most helpful comment

This is intended behaviour.

Observable.forEach() is an alias for Observable.subscribe(), according to the rxjs documentation

In order to iterate through a FirebaseListObservable:

// this.items is an Observable. You could use .forEach here too, but I find that confusing.
this.items.subscribe(items => {
    // items is an array
    items.forEach(item => {
        console.log('Item:', item);
    });
});

The array might be empty the first time but it shouldn't matter in most cases. If you need to do anything only when there is actual data, just wrap it in a if (items.length).

All 14 comments

Thanks for using the issue template! Let me take a look and see what the intended behavior here is.

Hello,
I had the same issue with
this.af.database.list('/items', {
query: {
orderByChild: 'im',
equalTo: 'cool'
}
}).subscribe(snapshot => { console.log(snapshot );});

Expected behavior

I expect console.log(snapshot ) to print out :
[{ im: 'cool' }]

Actual behavior
What is actually printed out

[]
[{ im: 'cool' }]

I added then something like :
.subscribe(snapshot => {
if(snapshot.length > 0){
console.log(snapshot );
}
});

This is intended behaviour.

Observable.forEach() is an alias for Observable.subscribe(), according to the rxjs documentation

In order to iterate through a FirebaseListObservable:

// this.items is an Observable. You could use .forEach here too, but I find that confusing.
this.items.subscribe(items => {
    // items is an array
    items.forEach(item => {
        console.log('Item:', item);
    });
});

The array might be empty the first time but it shouldn't matter in most cases. If you need to do anything only when there is actual data, just wrap it in a if (items.length).

So even if you use the subscribe method, I'm still getting the same issue. Perhaps this is just how the subscribe process works.

Say I have a list of 2 items. My subscribe method is called 3 times (even when using subscribe):

$ Item: []
$ Item: [{ im: 'cool' }]
$ Item: [{ im: 'cool' }, { again: 'yep' }]

Is there a more proper way of querying the list of data with AngularFire to get
back all the data at once, instead of in pieces?

@sean-hill , It is what I am trying to explain in my previous post, I am having the same issue with the subscribe method. As @Maistho told us,

Observable.forEach() is an alias for Observable.subscribe()

As I understand it, an Observable is asynchronous so there is no way to retrieve your list only once as the complete array using subscribe() or forEach() . You would need a promise instead of an Observable for that.

So I see 2 possibilites,
1- You deal with the multiple console.log('Item:', item);
2- It seems to be possible to use maps : .map .flatMap as a workaround,
cf : http://stackoverflow.com/questions/38259038/getting-data-out-of-firebase-object-with-angular2-angularfire2-and-typescript

@sean-hill Do you get the data back in chunks of one Object at a time even if it is available in the firebase database to begin with?

The returned array should always contain all items that have been added to the firebase database at that location. (sometimes it might be empty even though it's not? It works that way with auth)

@Maistho that is correct. I'll try and make a jsfiddle that shows the issue.

@Maistho take a look at this repo and follow the guide in the README to replicate the issue.

@sean-hill That does seem like a bug. Weird, I have not experienced that myself.

Inspecting the websocket shows me that the data only arrives once, and as far as I can tell from this code, the observable should not trigger next multiple times.

Try setting the subscription in the constructor or ngOnInit and see if the same issue appears again.

Also, I see that you have included a newer version of firebase in your package.json, maybe try removing that (it's included with angularfire2) as well?

@Maistho I removed the firebase dependency, which I installed from the Installation Instructions:

$ npm install firebase angularfire2 --save

Still had the same problem. I'll try setting up the subscription in the constructor. My use case though for this flow was this. I wanted to create a list of items, and then copy that list of items and push them all into a separate collection. AKA, the first list of items was a template, and then I would take those items and turn them into actual commands that a process would run. Perhaps it's not a firebasey why of doing things 馃槂

I can't reproduce anything unexpected by creating a list and calling push(). The initial list is loaded with no data, when an item is added, the subscription is updated with the new value, and so on. Since there's not enough code in the repro here to recreate the conditions you've described (just some random snippets described as "in another function") I'm going to close this.

Feel free to resubmit with a minimal, verifiable, complete, example, such as this one that demonstrates some unexpected behavior and I'll be happy to continue the discussion.

@katowulf did you take a look at the example repo I posted above? It shows the exact issue when you open the console along with the code base that causes it.

@katowulf in addition to the repo I already provided above, I just forked your plunker to show the issue also. View it here. Just open your console and click "View all".

Thanks! Turns out this is a dup of #574. The issue is that multiple subscribers cause some internal Firebase caching to switch from async to sync, and this generates a race condition. ; (

Was this page helpful?
0 / 5 - 0 ratings