I'm working on Angular 5 Project, that need to be fast and responsive while fetching a gigantic object from server. In order to make app run faster, the object [Word Document] is broken down into main components [Word Pages]. Inside main components, there is a router outlet that load sub-components [Paragraph].
I've given an example of the big object as a word document, which contain pages and paragraphs. Due to complexity of getting these data from different systems, and the heavy weight of these objects, I've decided to compose these small parts into the main object named BCA.
When user navigate to BCA/:id/home/summary that will load the data of the summary sub-component. meanwhile, on the background a chain of API calls running to fetch the other parts [home/date, home/load, audit/summary, etc.] composing the main BCA object.
User doesn't have to wait until the entire object is fetched, and he can see a result right away while is object is being fetched.
The problem I'm facing is how to trigger a sequence of API calls that can run in parallel, and report its progress to the UI. So user will know that the given tab or sub-component is loaded and ready to view. With the ability to cancel the entire chain if user navigate away.
Not sure if Observable can help, also how can I run this chain list that report its status and can cancel the entire list, what operator to use and if any example outside that demonstrate the same scenario.
Thank you for your help.
Typically I think people should come with something they've tried and ask questions about errors they've received, but I will give a simple example that isn't necessarily copy/paste-able so you can use it as a learning example to implement your own logic.
Here is how you can...
I will just use a simple, ugly and pragmatic approach using flags; you can make it prettier and more re-useable if you'd like.
import { Component, OnInit, OnDestroy } from '@angular/core';
import { forkJoin } from 'rxjs/observable/forkJoin';
import { finalize } from 'rxjs/operators';
import { MyService } from 'services';
export class MyComponent implements OnInit, OnDestroy {
foo: any;
loadingFoo: boolean = true;
bar: any;
loadingBar: boolean = true;
baz: any;
loadingBaz: boolean = true;
constructor(private myService: MyService) {}
ngOnInit() {
this.sub = forkJoin([
this.myService.getFoo().pipe(
finalize(() => this.loadingFoo = false)
),
this.myService.getBar().pipe(
finalize(() => this.loadingBar = false)
),
this.myService.getBaz().pipe(
finalize(() => this.loadingBaz = false)
)
]).subscribe((responses: any[][]) => {
this.foo = responses[0];
this.bar = responses[1];
this.baz = responses[2];
})
}
ngOnDestroy() {
if (this.sub) {
this.sub.unsubscribe();
}
}
}
And the template can look like so:
<ng-container *ngIf="loadingFoo">
<loader></loader>
</ng-container>
<ng-container *ngIf="!loadingFoo">
<foo-component [foo]="foo"></foo-component>
</ng-container>
<ng-container *ngIf="loadingBar">
<loader></loader>
</ng-container>
<ng-container *ngIf="!loadingBar">
<bar-component [bar]="bar"></bar-component>
</ng-container>
<ng-container *ngIf="loadingBaz">
<loader></loader>
</ng-container>
<ng-container *ngIf="!loadingBaz">
<baz-component [baz]="baz"></baz-component>
</ng-container>