Search code examples
angularobservablerxjs6rxjs-observablescombinelatest

Combine two observables inside pipe() chain


I'm using Rxjs, and I want to create an Observable from the following pattern (in order):

  1. get params from paramMap$, then ...

  2. based on the value of params, get both (getData():Observable, getCategories():Observables) together, then ....

  3. from ([data, categories]) create the final object.

The code would look like:

//route = this.ActivatedRoute

let obs$ = route.paramMap.pipe(

// combineLatest() is not a pipable operator, so it shouldn't be used inside .pipe()
// also it doesn't accept a function,
// but this just to show you what I want to do.

combineLatest(params=>getData(params.id), params=>getCategories(params.id)),

map(([data, categories])=>{
//do some changes...
return {data,categories}
}
)
)

also where is the best place to put this code in Angular project:

  • constructor() is not the best practice, because this is a long-running operation (actually it has to do API requests)

  • ngOnInit() is not recommended, because in some point I have to change this.params which is used in the template

...
combineLatest(params=>
   getData(params.id).pipe(
        map(data=>{
            this.params.type=data.type; 
            return data
           })), 
   params=>getCategories(...) 
)

in template:

<div>{{params.type}}</div>

Solution

  • For piping the Observable after you get params, you can use switchMap and return a forkJoin() from within it.

    this.route.paramMap.pipe(switchMap((params) => {
        return forkJoin(getData(params.id), getCategories(params.id));
    }));
    

    I believe, subscribing an Observable, doing API requests, all should ideally go to ngOnInit() unless you have some very specific requirement where you do not want these subscriptions when the component loads.

    As far as this.params is concerned, you can assign this.params under either using a piped tap() or where you do a subscription for this Observable.