Reputation: 6875
I have two service in my application.
@Injectable()
export class SettingService {
private settings = new BehaviorSubject<any[]>([]);
constructor(private http: HttpClient) {
this.loadSettings();
}
private loadSettings() {
this.http.get<any[]>('/api/settings')
.subscribe((settings) => this.settings.next(settings));
}
getSettings() {
return this.settings.asObservable();
}
}
@Injectable()
export class InformationService {
private informations = new BehaviorSubject<any[]>([]);
constructor(private http: HttpClient) {
this.loadSettings();
}
private loadInformations(appId: string) {
this.http.get<any[]>('/api/informations/appId')
.subscribe((informations) => this.informations.next(informations));
}
getInformations(appId: string) {
return this.informations.asObservable();
}
}
And I am using these service instances in my app controller.
@Component({
selector: 'calc',
templateUrl: 'calc.component.html',
styleUrls: ['calc.component.css']
})
export class CalcComponent {
constructor(informationService: InformationService, settingsService: SettingService){
// settingsService.getSettings()
// and use settings.appId to get informations.
// informationService.getInformations(settings.appId)
}
}
How can I call services by order? I am new at rxjs.
Upvotes: 0
Views: 61
Reputation: 66
It sounds like you want the calls loadSettings
and loadInformation
to happen in a certain order? If you want them to finish at the same time then I would go with forkJoin(loadSettings(), loadInformation())
, it's the analog to Promise.all
. If you want things to happen in a certain order then I agree with the above answer of switchMap
.
I wouldn't go so far as to say that the above architecture is not a best practice. It depends, here is a good article on the different patterns with HTTP.
Upvotes: 0
Reputation: 9124
Your approach with these BehaviorSubjects is not really best practice.
First of all, remove those any types. Create an interface.
export interface Setting {
// whatever comes here
}
export interface Information {
// whatever comes here
}
You don't need a service for every API endpoint, let's create only 1 here. You include both endpoints in this service. They return the Observable.
@Injectable()
export class MyService {
constructor(private http: HttpClient) {}
public loadSettings(): Observable<Setting[]> {
return this.http.get<Setting[]>('/api/settings');
}
private loadInformations(appId: string): Observable<Information[]> {
return this.http.get<Information[]>('/api/informations/appId');
}
}
Then in your Component you can do something like this:
@Component({
selector: 'calc',
templateUrl: 'calc.component.html',
styleUrls: ['calc.component.css']
})
export class CalcComponent {
settings$: Observable<Setting[]>;
informations$: Observable<Information[]>;
constructor(private myService: MyService){
this.settings$ = myService.loadSettings();
this.informations$ = this.settings$.pipe(
switchMap(settings => myService.loadInformations(myAppId)), // whereever myAppId comes from
);
}
}
Subscribe to it in your template with async pipe.
Upvotes: 1
Reputation: 11982
You can use rxjs switchMap operator:
settingsService.getSettings().pipe(switchMap(res1 => {
informationService.getInformations(res1.appId)
}).subscribe(res2 => {
console.log(res2)
})
Upvotes: 0