Reputation: 239
I have an array of objects that only sometimes require a service call. The objects that require a service call take awhile to fill, so I end up with an array of the objects that didn't require a service call and then the rest at the end.
I've tried async / await, promise, and just regular subscription. Im very shaky with rxjs so I'm not sure if there's a better way to do this with observables and pipable operators
public getComments(cars: any) {
cars.forEach( async car => {
if(car.status === '1') {
// trying async / await
let repairs = await this.service.getComments(car.carId)
car.repairs = repairs
this.carRepairs.push(car)
// regular subscribe
// this.service.getComments(car.carId).subscribe(result => {
// car.repairs = result
// this.carRepairs.push(car)
// })
// trying promise
// this.service.getComments(car.carId).toPromise().then(result => {
// car.repairs = result
// })
} else {
this.carRepairs.push(car)
}
})
}
If anyone knows of a better way to do this with rxjs and keep the order, I'd love to learn.
Upvotes: 0
Views: 542
Reputation: 29335
so first you're gona want to map all of your items into an observable, even if they don't need to be observables, then you join them together:
import {forkJoin, of} from 'rxjs';
import {map} from 'rxjs/operators';
public getComments$(cars: any) {
const results$ = cars.map( car => { // map the array into observables
if(car.status === '1') {
// return service call observable
return this.service.getComments(car.carId).pipe(
// ** see note on this **
map(repairs => Object.assign(car, {repairs})) // add result to car and map to the car
);
} else {
// return mock observable;
return of(car);
}
});
// return all observables joined together
return forkJoin(results$);
}
then you can just call it and subscribe to the result:
this.getComments$(this.cars).subscribe(carRepairs => {
// do whatever here
this.carRepairs = carRepairs;
});
this will ensure that the carRepairs
are in the same order as cars
.. all the needed requests will run in parallel, but you could do this sequentially by using concat
instead and slightly modifying your subscribe function, if you want to preserve some kind of cascade effect.
note: I preserved a side effect from your original code where you mutate the objects in your cars array, normally, I wouldn't do that and I'd do Object.assign({}, car, {repairs})
to ensure I don't produce side effects. side effects and mutation are often a source of bugs and should be avoided when ever possible.
Upvotes: 2