Best practice: Nested subscriptions to receive user data?

I’m going to also suggest, based on your branching needs, maybe you just simplify things and use spawn / await. I’d say just simplify to promises and use async / await but I don’t think we get that until TS 2.1, and Ionic is only on 2.0.9 last I checked.

The biggest difference I’ve found between AF and Observables is what happens when a null value (nothing at the address requested) is encountered in the database. In that case, Firebase emits anyway, providing a key-value pair where the key is the key from your query, and the value is null. This is different from the regular response, where you just get the value back. The design point is that the primary objective of AF is to be unwrappable by the async pipe. Honoring rxjs operators is of secondary importance, and only sometimes works as expected, even if typings thinks the operator is ok to add to, e.g., the FirebaseObjectObservable.

The specific issue you quoted me about arises from the functionality here:

It appears that the only way to get access to $exists is to use subscribe. At the very least, I failed utterly when trying to use rxjs operators instead, because AF only emitted obj when I subscribed. So the subscription helps cause the emission, instead of just observing it. If you succeed where I failed, I’d like to know, because I try to use subscribe as little as possible.

Edited to add: The parts of the Firebase 3 API I’ve used were all correct, and it looks as though a lot of work has gone into them, so I assume they are stable. But the OP is using AngularFire2, which is the official project that connects Firebase to Angular 2. That’s what is not yet fully (or correctly) documented. So you can avoid some time sinks if you just use the Firebase API. But if you want simpler code that leverages Angular 2, esp the async pipe, then AngularFire2 is the library.

This sounds like what I find to be one of the more arcane and confusing aspects of Rx: hot versus cold observables.

I decided to move the IF statement out of the flatmap “queue”. Looking like this (simplified), it still feels somehow nested, but for me better than throwing an error:

   functionA(userId).subscribe( data => {

      if (data.automatic_activity_detection === true) {
        
        // START automatic detection
        functionB
        .flatMap( result => {
          return functionC(userId, result)
        })
        .catch( error => { 
          this.errorService.handleError(error);
          return Rx.Observable.of(error) 
        })
          
        .subscribe( () => {
          console.log("Success");
        }, error => {
          this.errorService.handleError(error);
        });

      } else {
        // STOP HERE
        console.log("No automatic activity detection.")
      }
    }, error => { 
      this.errorService.handleError(error);
      return Rx.Observable.of(error) 
    });

I don’t really know, how to apply your advice to the above code-example.
How could I change:

functionB
.flatMap( result => {
    return functionC(userId, result)
})

to this

functionB
.flatMap(functionC)

and still pass over “result” and “userId”?

Additionally, is the error handling fine the way i do? Or would you recommend another approach here?

I think throwing an exception works if you are happy for the subscriptions to end. When working with hot observables I avoid throwing exceptions and tend to return Observable.of(undefined) when I need to drop through the chain.

Like so:

functionA()
.flatMap( data => {
  if (data) {
    // continue with functionB
    return functionB()
  } else {
    return Observable.of(undefined);
  }
})

 // everything from here on is only to be called if the case is true.  
.flatMap( data2 => {
  if(data2) {
    return functionC(data2);
  } else {
    return Observable.of(undefined);
  }
})
  
.subscribe( (data3) => {
  if (data3) {
    console.log(data3);
  }
});

This keeps the chain of subscriptions active. From what I understand, if any of the subscriptions receive new values then the rest of the chain is executed from that point on. I can confirm that the first subscription causes the chain to re-execute, but I don’t actually have examples in my applications where subscriptions in the middle of the chain receive new values, but I believe it works that way.

The downside to this approach is that you have to use this logic for the remainder of the chain. But I find that the pattern works well and is reasonably easy to read.

Glenn.