Why is my loading spinner of my child component never shown?

Viewed 357

I have an angular component "map". This component loads some child components in its template:

...
<app-route-dialog (addRouteEvent)="addRoute($event)"></app-route-dialog>
<app-route *ngFor="let route of routes" 
    [route]="route" 
    [map]="map>
</app-route>
...

The user can load routes from an api by opening the route dialog, filling in a form and submitting it to the server. This triggers

addRoute(route:Route):void {
    this.routes.push(route);
}

on the map component, which in turn adds another "route" component to the map view.

The template of the route component looks sth like this:

<div *ngIf="loading">
    <mat-spinner></mat-spinner>    
</div>
<table *ngIf="!loading">...some route data ... </table>

The component itself

...
@Input() route: Route;
@Input() map: L.Map;
loading = true;
...
ngOnInit(): void {
    // create and add some layers to the map this takes a couple of seconds depending on the data
    this.loading = false;
}

Expected behavior: After addRoute($event) gets called, the added route component should be rendered and show a loading spinner. After creating and adding all Elements for the map, the loading spinner should disappear and a table with data for the loaded route should be displayed.

Actual behaviour: After addRoute($event) nothing happens for a couple of seconds, then the new route component is rendered with the route data table. The loading spinner is never shown.

Edit: I am iterating over an array and creating a map marker for each point in that array. The asynch call to the api happens in the dialog component and is finished before that.

ngOnInit():void {
    const factory = this.resolver.resolveComponentFactory(LeafletTooltipComponent);
    for(let routePoint of this.route.points) {
        let marker = new L.CircleMarker([routePoint.lat, routePoint.lng],{});
        let tooltip = new L.Tooltip();
        let component = factory.create(this.injector);
        component.instance.routePoint= routePoint;
        component.changeDetectorRef.detectChanges();
        let tooltipContent = component.location.nativeElement;
        tooltip.setContent(tooltipContent);
        marker.bindTooltip(tooltip);
        this.markers.addLayer(marker); // markers = L.FeatureGroup
    }
    this.loading = false;
 }

Edit 2: When ditching

let component = factory.create(this.injector);
component.instance.routePoint= routePoint;
component.changeDetectorRef.detectChanges();
let tooltipContent = component.location.nativeElement;
tooltip.setContent(tooltipContent);
marker.bindTooltip(tooltip);

and instead doing sth like

setTimeout(() => {this.loading = false;}, 3000);

everything works as expected.

2 Answers

It seems that creating the layer new L.CircleMarker([routePoint.lat, routePoint.lng],{}); and adding it to the group this.markers.addLayer(marker); take some times until finished, but both of them don't prevent the execution to continue.

So I think you need to listen to the add event of the CircleMarker, then change the loading state within its callback.

First, you can test it for one route only, and if it's okay, you can implement some kind of buffer to know that all the routes have been added before changing the loading state.

You have to set boolean variable into ngOnInit, It's Wokring for me.

...
@Input() route: Route;
@Input() map: L.Map;
loading = false;
...
ngOnInit(): void {
    this.loading = true;
    // Your Code..............
    this.loading = false;
}
Related