I have two Observables. The rendering of the template should only start when BOTH Observables are completed or failed:
- Observable 1 completes and Observable 2 completes or
- Observable 1 completes, but Observable 2 fails
- When Observable 1 fails Observable 2 is not important because the template won't be rendered completely then
(Ignore the <any>
type, it's only for simplification here)
Component:
@Component({
selector: 'app-page',
templateUrl: './page.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PageComponent implements OnInit {
obs1$ = new Subject<any>();
obs2$ = new Subject<any>();
isLoading = true;
isObs1Error: boolean;
isObs2Error: boolean;
ngOnInit() {
this.initializeDataRetrieval();
}
initializeDataRetrieval() {
this.obs1$ = this.obs1Method();
this.obs1$.subscribe((response: any) => {
this.isObs1Error = false;
this.obs1 = response;
this.obs2$ = this.obs2Method();
this.obs2$.subscribe((response: any) => {
this.isObs2Error = false;
this.isLoading = false;
this.obs2 = response;
this.cdr.detectChanges();
});
});
}
private obs1Method(): any {
return this.obs1Service
.getStuff()
.pipe(
catchError(() => {
this.isError = true;
this.isLoading = false;
this.cdr.detectChanges();
return EMPTY;
})
);
}
private obs2Method(): any {
return this.obs2Service
.getStuff()
.pipe(
catchError(() => {
this.isObs2Error = true;
this.isLoading = false;
this.cdr.detectChanges();
return EMPTY;
})
);
}
canDisplayContent(): boolean {
return !this.isLoading && !this.isObs1Error;
}
Template:
<ng-container *ngIf="isLoading">
<app-loading-indicator></app-loading-indicator>
</ng-container>
<ng-container *ngIf="isObs1Error">
<div class="error">
This Obs1 stuff could not be loaded currently
</div>
</ng-container>
<ng-container *ngIf="canDisplayContent()">
<div class="error" *ngIf="isObs2Error">
Technical error
</div>
More content here which is shown when at least Obs1 doesn't had an error
</div>
So basically:
- I wanna wait with template rendering until both Observables are done and display a loading indicator during the time
- When there is an error with Obs1 then show a message
- When there is an error with Obs2 then render the 3rd
ng-container
with the Obs2 error message
I'm sure the TS code can be simplified by the usage of ... which RxJS operator? Although reading through RxJS Operators for Dummies: forkJoin, zip, combineLatest, withLatestFrom I'm not sure if any of these fits. As far as I understood e.g. combineLatest
only succeeds when both streams complete successfully ...
Any hint is welcome, thanks.