Context
In an Angular application, I have three <select>
boxes that are fed from the database with a relatively small data set. These boxes are part of a filter Component
that is displayed next to a server-side data table. The component outputs the filter asynchronously to the parent component, which then pipes into the table, invokes server, filters out SQL etc.
Focusing on the scope, when the control is loaded, I want to invoke the server with three GET
invocations. Until they complete, I want to display a spinner.
Since I am using a library of controls, part of the code is already done. I want to ask here if I am handling the Observable
s correctly from the Angular point of view
Code I wrote so far
The code works
export class MyComponent implements OnInit, OnDestroy {
public filterLoading$: BehaviorSubject<boolean>;
public select1: Observable<string[]>;
public select2: Observable<string[]>;
public select3: Observable<string[]>;
private filterLoadingSub$?: Subscription;
constructor(private remoteService: RemoteService) {
this.select1 = remoteService.getFirst();
this.select2 = remoteService.getSecond();
this.select3 = remoteService.getThird();
this.filterLoading$ = new BehaviorSubject<boolean>(true);
}
ngOnInit(): void {
this.filterLoadingSub$ = forkJoin([this.select1, this.select2, this.select3])
.subscribe(() => this.filterLoading$.next(false))
;
}
ngOnDestroy(): void {
if (!!this.filterLoadingSub$) {
this.filterLoadingSub$.unsubscribe();
}
}
}
Explanation:
selectX
are bound to the front end with<option *ngFor="let x of (selectX | async)" ...>
- The subject
filterLoading$
is used to display the spinner. Actually my custom accordion handles it for me<acme-filter-panel isLoaded="!(filterLoading$ | async)>
- Then I used
forkJoin
operator to wait for the completion of all three calls. I don't care about the last returned valued, only that the three have completed. But this leads to aSubscription
- Under the philosophy of dispose your own garbage, every time I hit a
Subscription
I always write code to unsubscribe. However, these are just HTTP calls that return only once when invoked.
I truly understand that I am not handling error logic, but really that goes beyond the scope of the question
Questions
My question is about two aspects.
Apart from moving code from constructor to ngOnInit
, on reasons of symmetry, am I writing too much code or is there some simplification I can use to say Angular to unlock the spinner when all of the three invocations occurred?
Is it always necessary to always unsubscribe from subscriptions? Or are there cases in which a dangling subscription harms none? I learned that subscriptions use memory, so I deem necessary to clean up resources whenever possible, even if modern machines have gigabytes of RAM.
More in general, is it possible to write this piece in a more concise way? For three data sets I had to instantiate a fourth member, which is actually needed to monitor the spinner, and a fifth member used only on destruction to clean up. I often work with Observables & co.