There are essentially 2 options:
Is the option you have where you use forkJoin()
to combine all the observables into an array
- PROS: you know you will have all your data loaded inside you
subscribe()
- CONS: you have to wait for every HTTP request to finish before
forkJoin
emits the value
- Note: you can implement a nice helper function like @Prince recommended
You can use mergeMap()
for your IDs and react whenever one of the observables completes
- PROS: you don't have to wait for every HTTP request to complete. You can react as they complete. Also, you can handle errors easier (so if one request fails you can still continue with the other requests).
- CONS: you have to handle your emitted values in the
.subscribe()
a little differently
At the end of the day, you will need to decided which approach is best for you. There isn't anything wrong with the implementation you have. I noticed you are keeping your loadedCharacter
as an object, so honestly option 2 may be good for your use case
Example code for Option 2. See this stackblitz for a small demo:
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, from, Subject } from 'rxjs';
import { mergeMap, takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: 'app/app.component.html'
})
export class AppComponent {
private endSubs$ = new Subject();
loadedCharacter: {};
constructor(private http: HttpClient) {}
ngOnInit() {
/* ids of all the characters you want to load*/
const characterIds = [1, 2];
/* this will emit each id as a value */
from(characterIds).pipe(
/* merge each id to an Observable of the http get request */
mergeMap(id => this.http.get(`https://swapi.co/api/people/${id}`)),
/* cancel any pending requests when the component unloads.
this will avoid any RxJS memory leaks */
takeUntil(this.endSubs$)
).subscribe(
character => {
/* note that you will only receive 1 character at a time */
console.log('received character', character);
this.loadedCharacter[character.id] = character; // or whatever you want to do
},
err => console.log('Error loading a character', err),
() => console.log('All character requests have finished')
);
}
/* clean up our subscriptions when the component destroys */
ngOnDestroy() {
this.endSubs$.next();
this.endSubs$.complete();
}
}
EDIT: I added some RxJS cleanup code to avoid any memory leaks from the mergeMap
. Any requests that are pending when this component unloads will be cancelled. Here is an example SO answer explaining Observable cleanup, and here is a relevant RxJS article on where to place your takeUntil()
.