Patrick Patrick - 6 months ago 48
AngularJS Question

RxJS Observable.concat: How to know where next result came from?

My application (Angular 2 with RxJS 5 written in TypeScript) requires me to make 2 calls to a web service in a predefined order. Inspired by this page I decided to try the

concat
operator of RxJS observables. The twist is that the
onNext
callback that receives values needs to forward them to different handlers depending on where they came from

My code can be simplified to:

suscription1 = Observable.return({name:'John', age:7});
subscription2 = Observable.return({name:'Mary', color:'blue'});
Observable.concat(subscription1, subscription2).subscribe(
data=>{ /* need to know which subscripion
i'm dealing with to direct to the right handler*/}
);


What's the most elegant way to determine where my data came from at each observable emission? I have thought of a couple of ways but they all seem clumsy:


  1. Keep a counter in scope, perhaps as a class property. Check it and increment it each time you receive a result. Since each observable emits just once, the counter will have its initial value when the first subscription outputs and it will have initial+1 when the second outputs. Problem is this won't work when I don't know how many times each observable will emit before being complete.

  2. Inspect each result and identify its source by the result's shape. For instance, in my example only the first observable's result has an
    age
    property. Obviously this becomes impractical when the results have the same shape.

  3. Get rid of the
    concat
    operator altogether; subscribe to
    subscription2
    in the
    onComplete
    handler of
    subscription1
    . This would work, but it doesn't scale well; if I have 4 or 5 subscriptions to concatenate, it becomes nested hell.



Solution 3 with just 2 subscriptions...

suscription1 = Observable.return({name:'John', age:7});
subscription2 = Observable.return({name:'Mary', age:8});
subscription1.subscribe(
data=> this.handlerOne(data),
error=>{},
()=> {
subscription2.subscribe(
data=>this.handlerTwo(data),
error=>{},
()=>console.log('All subscriptions completed!')
)
}
);


So my question: When using
Observable.concat
to subscribe to several observables in sequence, how can my
onNext
handler determine where the data came from? Alternatively, is there another operator I should be using for this purpose? I cannot use the
forkJoin
operator because the order in which the subscriptions are completed is important.

Answer

You could mapthe suscriptions to know where it's coming from.

suscription1 = Observable.return({name:'John', age:7})
         .map(person => { person.source = 1; return person };
subscription2 = Observable.return({name:'Mary', age:8})
         .map(person => { person.source = 1; return person };

Then you can easily determine where it comes from:

Observable.concat(subscription1, subscription2).subscribe(
    data=> { if (data.source == 1) /* do whatever */ }
);
Comments