I have an issue with the Angular 14 which is not updating the view when querying data.
I want to show a loading spinner in my HTML when data are being loaded from the server. I am using ngbTypeahead
for suggestions/hints. When I set the boolean value in the function, it does not show anything in the view. I tried using NgZone
and run
method for Angular force view update but seems not working for me.
Here is the TS
public isLoadingVisible: boolean = false
public suggestStations: OperatorFunction<string, Array<Station>> = (text$: Observable<string>) => {
this.zone.run(() => this.isLoadingVisible = true)
const suggestion = text$.pipe(
debounceTime(200),
distinctUntilChanged(),
switchMap((searchText: string) => this.dataService.suggestStations(searchText.toLowerCase())),
);
this.zone.run(() => this.isLoadingVisible = false)
return suggestion
}
// Also tried to put loading into the switchMap function, nut not working as well
public suggestStations: OperatorFunction<string, Array<Station>> = (text$: Observable<string>) => {
return text$.pipe(
debounceTime(200),
distinctUntilChanged(),
switchMap((searchText: string) => {
this.zone.run(() => this.isLoadingVisible = true)
const result = this.dataService.suggestStations(searchText.toLowerCase())
this.zone.run(() => this.isLoadingVisible = false)
return result
}),
);
}
HTML View
<p *ngIf="isLoadingVisible">Loading...</p>
<div class="input-group mb-4">
<input [(ngModel)]="selectedStation"
[editable]='false'
[inputFormatter]="formatter"
[ngbTypeahead]="suggestStations"
[resultFormatter]="formatter"
[resultTemplate]="station_row"
class="form-control p-2"
placeholder="Název stanice"
type="text">
</div>
Do you please have any idea, where might be the issue? Thanks a lot for your help!
It looks like ngbTypeahead
internally subscribes to suggestStations
. What you have in both cases is incorrect because you don't wait for the inner Observable to complete or you change isLoadingVisible
outside of the chain.
So what you should do is putting isLoadingVisible
into the chain and make sure you trigger change detection yourself.
constructor(
private cdr: ChangeDetectorRef,
) {}
...
public suggestStations: OperatorFunction<string, Array<Station>> = (text$: Observable<string>) => {
return text$.pipe(
tap(() => {
this.isLoadingVisible = true;
this.cdr.markForCheck();
}),
debounceTime(200),
distinctUntilChanged(),
switchMap((searchText: string) => this.dataService.suggestStations(searchText.toLowerCase())),
tap(() => {
this.isLoadingVisible = false;
this.cdr.markForCheck();
}),
);
}