Hi all,
When querying fb with a FirebaseListObservable like so:
let items = this.angularFire.database.list('/items', query{...}).subscribe(x => console.log(x));
the output will be something like:
[Object, Object, Object, Object]
However when attaching two subscribers, each subscriber is triggered each time an item is added to the results array. for example:
let items = this.angularFire.database.list('/items', query{...});
items.subscribe(x => console.log('Subscriber 1: ', x));
items.subscribe(y => console.log('Subscriber 2: ', y));
// output:
Subscriber 1: []
Subscriber 1: [Object]
Subscriber 1: [Object, Object]
Subscriber 1: [Object, Object, Object]
Subscriber 1: [Object, Object, Object, Object]
Subscriber 2: []
Subscriber 2: [Object]
Subscriber 2: [Object, Object]
Subscriber 2: [Object, Object, Object]
Subscriber 2: [Object, Object, Object, Object]
I would expect both subscribers to be called just once with the final array result. Is this an error in my implementation, or by design?
My goal here is to search a list and do something if no items are returned from the search, ie:
let items = this.angularFire.database.list('/items', query{...});
items.subscribe(x => console.log('Subscriber 1: ', x));
items.subscribe(x => {
if(x.length == 0)
// do something
});
I would create a plunker for this but it seems the af2 version used by plunker has a problem with facebook auth (but let's leave that for another issue ;) ):
@maxmumford I am just getting the final array result with two subscribers. This is my code
import {Component} from '@angular/core';
import {AngularFire, FirebaseListObservable} from 'angularfire2';
@Component({
selector: 'app-root',
templateUrl: `
<ul>
<li *ngFor="let item of items | async">
{{ item }}
</li>
</ul>
`,
})
export class AppComponent {
items: FirebaseListObservable<any>;
constructor(af: AngularFire) {
this.items = af.database.list('/items', {
query: {
orderByChild: 'size',
equalTo: 'large'
}
});
this.items.subscribe(x => console.log('Subscriber 1: ', x));
this.items.subscribe(y => console.log('Subscriber 2: ', y));
}
}
Hi @mukesh51 , thanks for the reply.
I think my original question phrasing was a bit misleading. The problem seems to occur when I have an active subscription to an entire list, and a second subscription to a subset of said list:
ngOnInit(){
// get all items
this.angularFire.database.list('/items').subscribe(items => {
console.log('Got items: ', items);
});
}
findType1(){
// get a subset of items
this.angularFire.database.list('/items', {query: {
orderByChild: "type",
equalTo: 1
}}).subscribe(items => {
console.log('Found items of type 1: ', items);
});
}
So when the component loads, we subscribe to the entire list of items at /items. Then later, we subscribe to a subset of /items through a query. The console output is as follows:
Got items: [Item, Item, Item, Item, Item, Item, Item, Item, Item, Item, Item, Item, Item]
home.component.ts:54 Found items of type 1: []
home.component.ts:54 Found items of type 1: [Item]
home.component.ts:54 Found items of type 1: [Item, Item]
home.component.ts:54 Found items of type 1: [Item, Item, Item]
home.component.ts:54 Found items of type 1: [Item, Item, Item, Item]
home.component.ts:54 Found items of type 1: [Item, Item, Item, Item, Item]
home.component.ts:54 Found items of type 1: [Item, Item, Item, Item, Item, Item]
Finally if I remove the code in ngOnInit (so there is only one subscription at a time), the result is as I expect:
Found items of type 1: [Object, Object, Object, Object, Object, Object]
Is this behaviour intended? How should I go about accessing a subset of the main list?
Hi @maxmumford I tested your code as is and it works fine. Pasting below for your reference.
ngOnInit() {
this.af.database.list('/items')
.subscribe(items => console.log('In ngOnInit() ', items));
}
constructor(private af: AngularFire) {
af.database.list('/items', {
query: {
orderByChild: 'size',
equalTo: 'large'
}
}).subscribe(x => console.log('In Constructor: ', x));
i didn't remove any code from ngOnInit() and it worked as expected. Strange the same code is not working for you.
@davideast any thoughts ?
Hmm strange... I'll upload a new project demonstrating the problem this
weekend.
@mukesh51 please find at the link below a new project that demonstrates this issue:
https://github.com/maxmumford/multiple-subscriptions
Thanks
I am having the same issue, the first time subscribe loads, it gives me the entire array, the second time I enter the component I am having the above described output.
@storatus +1
This will let the app crash when navigate back and forth
In the meantime getting the data as an object works for me, instead of list.
I looked at the angularfire 2 code and I assume it has to do with the 'once' method from firebase which is called when the component initiates for the first time and delivers the corresponding array.
Leaving and entering the component again wont respond to 'once', since it has been already called, so I think angularfire 2 uses then child_added method instead, which will cause this kind of behaviour.
Found 2 other issues referencing this problem:
I have the same issue.
It works fine if you query the data from the constructor, but it crashes really badly when you query it from lifecycles.
I find this very annoying because I need some data to load in order to do some queries in my project 馃槱
I agree with @storatus that it's something with the once value in firebase_list_factory
Like it fires too fast.. I'd have to debug it to be sure but that's where I'd start.
Not really a fix to the weird list behavior for others but @maxmumford have you thought about the rx filter() operator?
you could do:
var allItems = this.af.database.list('items');
function getFilteredList(property:string, key:string) {
return allItems.filter(item => {
return item[property] == key;
});
}
If you are already loading ALL the items the query doesn't save you anything as the entire list is already loaded with the allItems list... No need to query firebase again...
@maxmumford @DennisSmolek @RaulGarafulic @storatus
I have found the issue, and it does have something to do with ref.once('value', ....
We use ref.once to tell us when the child events are done loading and then we start emitting your values. However, sometimes the Firebase SDK can fire off callbacks synchronously (this is something I somehow always forget). @maxmumford In your case the call is done synchronously. This causes Firebase to tell AngularFire2 that the child events have finished loading even though they have not, hence all of the extra calls.
The solution is to put the child events inside of the once call. I'm working on the fix now and should have something out shortly.
I also apologize for the long delay on this issue. I've been sick and been dealing with sick children for the past month and it's hard to be a functioning human being.
@DennisSmolek thanks, yes that's the workaround I used in the end. Load the entire list and cache it from within the subscriber, then instead of querying firebase, just filter that list.
@davideast thanks for the update, It'll be good to have the fix but as mentioned above I've got a feasible workaround so there's no real rush. No worries about the delay, it's that time of year, everybody seems to be getting sick atm. Hope you and your kids are better soon!
I was sure I missed something with observables until reading this! good to hear a fix is coming soon.
Thank you @davideast !
@storatus An object works, but there's any way to loop it? I need to use the list $keys in my app, so I need to loop each to get more data. Currently its impossible until fix is up.
@theunreal try to loop it with lodash _.each() method, there you can then iterate and the second parameter is the index which is the $key in angularfire2
Any news or ETA on this? Thanks for all the great efforts, @davideast and co.
I am also having a similar issue with .list()
My firebase database is:
{
users: {
richard : { },
stefany : [bookmark1,
bookmark2,
bookmark3]
}
articles : { }
}
When I access 'users', it gives me one result
[users]
When I try to access 'users/stefany' the following result produces:
[bookmark1]
[bookmark1,bookmark2]
[bookmark1,bookmark2,bookmark3]
When I use .object() it gives me one result:
[bookmark1,bookmark2,bookmark3]
In Conclusion: When I try to get deeper inside my database object with .list(), it will repeat for no reason multiple times...when I use .object(), it is not a problem
Hey team,
Any progress on this? This bug is affecting multiple parts of our application.
Thanks
@rosslavery Yes. This will be in the next release. I have the fix speced out, now just to implement it without breaking everything 馃敤
hey everyone, until then, in my project I am using .object() and just converting it to a list via .map() example:
var obj = {1: 11, 2: 22};
var arr = Object.keys(obj).map(function (key) { return obj[key]; });
@rosslavery
I've been doing that, but we lose the auto-adding of $key, $value, $exists, etc.
Obviously we could create similar code to perform the same data transformation, but I'm looking to avoid re-writing angularfire-specific code that will be fixed shortly.
So just hanging on until the fix is released.
Thanks though!
I think this will fix the issue I'm having also. I have an app where I'm adding values to a list using a subscription. It works fine on the initial load of the component, but if I leave the component and comeback, when I add a value to the list, it adds two subsequently. It seems that the subscription call is called twice also.
For my case, I unsubscribe the subscription call(s) on the component destroy (onDestroy()).
I seemed to have fixed the problem from this thread https://github.com/angular/angularfire2/issues/377 by calling first().
import 'rxjs/add/operator/first';
this.items.first().subscribe(snapshots => console.log(snapshots));
from @katowulf
@davideast @katowulf any update on this? We're close to launching a production app that is still affected by this issue. We've been using .debounce(somesmallnumber) as a workaround for now, but this one has been open for nearly 3 months now.
Not meaning to harass, just more concerned about the project's....velocity. I know you guys are juggling many different ____fire libraries though.
@rosslavery @maxmumford Super sorry about the delay on this issue. I've been slammed since switching roles. I had it fixed awhile back but it broke several tests, so there was a lot of plumbing work involved.
I just merged this in with #735, will get a @next release out soon. I would love your feedback on it if you have the time.
Thanks, It's working for my app.
The @next release also fixed it for us. Thanks @davideast!
Thanks. Works for us as well.
Happy new year and thank you for the great work.
Hey all,
i'm encountering the same issue - and i didn't understand the solution (sorry, i'm a rookie).
Just to treat everything as objects..?
How can I get the "@next" release?
thanks for your patience (:
@shaharido1, just run npm i angularfire2@next --save
beta.7 haven't solved it for me,
I am doing something like this:
this.af.database.object('data').subscribe((data) => {
this.af.database.list('list/+data).subscribe((myList) => {
this.myList = myList;
});
});
this.myList shows only the first item in the list
Thanks @davideast , the @next release fixes the issue on my project!
@theunreal
I had this issue with beta6.
Beta-7 did resolve it
Thanks @davideast
@davideast thanks for releasing this fix. I'm not using AF2 anymore as the project is now complete, but from everybody else's comments it looks like your changes did the trick!
I have this very simple observable
this.items = angularFire.database.list(databaseUri);
that my component subscribes to. Going from the list page to the details page and back again still produces the problem describes above.
The first time I enter the list of users I get this log
[User, User, User]
Coming back to the list page gives me this:
[User, User, User]
[User, User, User, User]
[User, User, User, User, User, User]
It is always reproducible the first time. Going back and forth between list and details afterwards results in diffrent results.
Adding the .first() operator does solve the problem.
I'm using: "angularfire2": "^2.0.0-beta.7"
@bregnvig Can you create a plnkr reproducing this issue?
Also, this issue is closed, so starting a new thread with a complete repro and details will be appropriate.
Now it works fine, don't miss "npm i angularfire2@next --save" guys before using .first() .take(1)
Just subscribe inside the ngOnInit() method
Is it possible that the bug has come back in 4.0.0-rc0 and 4.0.0-rc1?
I am having this issue with the current latest
Most helpful comment
@rosslavery Yes. This will be in the next release. I have the fix speced out, now just to implement it without breaking everything 馃敤