Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ForkJoin of observables remain cold #617

Closed
jeffarese opened this issue Oct 15, 2016 · 7 comments
Closed

ForkJoin of observables remain cold #617

jeffarese opened this issue Oct 15, 2016 · 7 comments

Comments

@jeffarese
Copy link

Version info

Angular: 2.0.0

Firebase: 3.4.1

AngularFire: 2.0.0-beta.5

Other (e.g. Node, browser, operating system) (if applicable):
Node 6.0.0
Windows 10
Any browser

Steps to reproduce

In any flat database, it's common to have to perform multiple queries to complete the object information.
For example, if I have a conversation node with a list of userIds, I would like to perform a query to the node users to retrieve the user information and then create my custom conversation object with all the data.
The problem is that, unlike normal HTTP calls to a REST API, when using a forkJoin with FirebaseObjectObservable or FirebaseListObservable elements, the resulting Observable of the forkJoin remains cold.

Perform any forkjoin of observables, like:

   this.af.database.list(`users/${user.id}/conversations`)
        .flatMap((conversations) => {
          return Observable.forkJoin(
            conversations.map((conversation) => {
              return Observable.forkJoin(
                this.af.database.object(`users/${conversation.receiverId}`),
                this.af.database.list(`messages/${conversation.$key}`)
              ).map((data)=> {
                conversation.destinationUser = data[0];
                conversation.messages = data[1];
                return conversation;
              });
            })
          );
       });

Expected behavior

The expected behavior is that I can subscribe to the resulting Observable and do things.

Actual behavior

The resulting Observable remains cold, it doesn't trigger anything inside the subscribe

@janein
Copy link

janein commented Oct 19, 2016

Hi,

just to confirm this - I ran into a similar problem:

Observable.forkJoin(
    loadSomething(),
    loadSomethingElse()
).subscribe(res => {
    console.log('ready', res);
});

-> my log never triggers

Note: loadSomething() and loadSomethingElse() are just placeholders for my real functions. They both return a FirebaseListObservable and when I subscribe to them individually they work totally fine as expected.

PS: I'm doing this inside a Ionic 2 RC1 application

Cordova CLI: 6.3.1 
Ionic Framework Version: 2.0.0-rc.1
Ionic CLI Version: 2.1.1                     
Ionic App Lib Version: 2.1.1           
Ionic App Scripts Version: 0.0.36   
OS: Windows 7 SP1 
Node Version: v4.6.0  

@cartant
Copy link
Contributor

cartant commented Oct 22, 2016

@jeffarese @janein I don't belive this is a bug. forkJoin joins the observables when they complete and a FirebaseListObservable or FirebaseObjectObservable doesn't complete.

If you use the first operator to complete the observable after the first emitted value, the forkJoin call should behave in the manner you expect.

The RxJS 5 documentation for forkJoin is non-existant, but the documentation for the previous version does mention this:

Runs all observable sequences in parallel and collect their last elements.

@davideast
Copy link
Member

Closing due to @cartant's explanation.

@jusefb
Copy link

jusefb commented Jan 24, 2017

I have tried to use first() in the forkJoin that did not work. Using take(1) did work however. Am I using the code incorrectly?

does not work

Observable.forkJoin(
                this.af.database.list('/rooms').first(1),
                this.af.database.list('/devices').first(1));

works

Observable.forkJoin(
                this.af.database.list('/rooms').take(1),
                this.af.database.list('/devices').take(1));

@afreix
Copy link

afreix commented Apr 10, 2017

@jusefb I believe it should be .first() with no arguments passed. With that being said, in my use case both .first() and take(1) seemed to work equivalently

@afreix
Copy link

afreix commented Apr 10, 2017

@cartant is there a way to have forkJoin emit a new event when the underlying Observables change due to changes to the Firebase database, so that the UI template can update automatically.

I place this in the constructor for a component and it fires when the page loads

Observable.forkJoin(
         this.dataService.getFriends(userId, AppSettings.REQUEST_QUERY_USER_ID).first(),
         this.dataService.getFriends(userId, AppSettings.REQUEST_QUERY_FRIEND_ID).first()
       ).subscribe(friends => {
         console.log("Friends: ", friends);
         this.friends = friends;
      });

but if I delete a friend while on the page, Firebase correctly updates, but subscribe doesn't fire again. If I subscribe to something more simple

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

then changes to Firebase are automatically reflected in my UI

@cartant
Copy link
Contributor

cartant commented Apr 10, 2017

@afreix No, that's not how forkJoin works. It's purpose is to wait until all of the observables passed to it have completed and have emitted at least one value.

It you want an observable that combines the the values and continues to listen, you should use combineLatest, which emits the latest values from each observable - once each has emitted at least one value - and continues to emit the combined values whenever an observable re-emits. And you probably don't want to use first if you are using combineLatest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants