0

I have an Angular app (13.0.2), with Angular Google Maps. I am also using agm markers.

In the template, I have a dropdown that filters the map points by type. While the filtering is in progress, I want to put a loading div, and hide the map. This is controlled by an isLoading boolean.

The problem is that whatever I do, it waits for the filter to happen, and only then renders the loading div. I logged the isLoading value, and it evaluates to true when it should, however it seems that Angular is waiting for the map points to finish filtering before rendering...

This is the dropdown in the template:

<div class="col-md-4">
   <div class="a-common-header">
        <label for="agm-tecnhology" class="color-light-blue h4">{{technologyLabel}}</label>
   </div>
   <div class="form-group">
        <select class="form-control installation-type-dropdown" id="agm-tecnhology" [value]="selectedInstallationType" (change)="onFilterByTechnology($event.target.value)" [disabled]="isLoading">
            <option value="all">{{showAllLabel}}</option>
            <option *ngFor="let technology of technologies" [value]="technology">{{ technology }}</option>
        </select>
    </div>
</div>

this is onFilterByTechnology, and the filtering method that it calls:

onFilterByTechnology(technology) {    
    this.isLoading = true;
    
    this.selectedTechnology = technology;

    this.filterByTechnology();   
}

filterByTechnology() {
    this.infoWindowOpened = null;  

    this.waypoints = this.waypointsInitial.filter((marker) => {
        return this.selectedTechnology === 'all' && this.selectedCountry === 'all' ?
                marker : 
                this.selectedTechnology === 'all' && this.selectedCountry !== 'all' ?
                marker.Country === this.selectedCountry :
                this.selectedTechnology !== 'all' && this.selectedCountry === 'all' ?
                marker.Technology === this.selectedTechnology :
                marker.Technology === this.selectedTechnology && marker.Country === this.selectedCountry;          
    });

    this.isLoading = false;
} 

and this is the map in the template:

<agm-map class="o-agm" [ngClass]="isLoading ? 'hide' : ''" [fitBounds]="bounds" [zoom]="defaultZoom" [minZoom]="2" [maxZoom]="18" [latitude]="latitude" [longitude]="longitude">
<appDirectionsMap [mapData]="mapData" (routeChanged)="routeChangedHandler($event)"></appDirectionsMap>
<ng-container *ngIf="hasRadius">
    <agm-circle *ngFor="let marker of waypoints" [latitude]="marker.Latitude" [longitude]="marker.Longitude" [radius]="circleRadiusInKm" [fillColor]="'#2777B8'" [fillOpacity]="0.4" [strokePosition]="0" [strokeColor]="'00205B'" [strokeOpacity]="0.4" [strokeWeight]="0.5" (circleClick)="circleWasClicked($event, circleInfoWindow)">
        <agm-info-window [latitude]="clickLat" [longitude]="clickLng" #circleInfoWindow>
            <ng-container [ngTemplateOutlet]="markerDetails" [ngTemplateOutletContext]="{marker:marker}"></ng-container>
        </agm-info-window>
    </agm-circle>
</ng-container>

<ng-container *ngIf="!hasRadius">
    <agm-marker-cluster [averageCenter]="true" [maxZoom]="17" [styles]="[{url: 'Frontend/assets/images/cluster.png', textColor: '#fff', textSize: '14', height: '36', width: '36'}]">
        <agm-marker *ngFor="let marker of waypoints" [style.backgroundColor]="red" [iconUrl]="'Frontend/assets/images/markerdarkblue.png'" [latitude]="marker?.Latitude" [longitude]="marker?.Longitude" (markerClick)="markerWasClicked(markerInfoWindow)">
            <agm-info-window [latitude]="clickLat" [longitude]="clickLng" #markerInfoWindow>
                <ng-container [ngTemplateOutlet]="markerDetails" [ngTemplateOutletContext]="{marker:marker}"></ng-container>
            </agm-info-window>
        </agm-marker>    
    </agm-marker-cluster>            
</ng-container> 

So I filter on technology, the isLoading is true, but the map doesn't get the hide class until after the filtering. When the filter is finished, the hide class is added, and I get the loading div, etc.

It is as if somehow the map is blocking the updating until filtering is finished. I tried forcing detectChanges(), to no avail.

Does anyone have an idea what I might be doing wrong?

Thanks a lot :)

downer
  • 27
  • 1
  • 9

2 Answers2

0

Maybe not an answer, but a workaround -

I added a timeout on filterByTechnology(), and now it works as it should.

setTimeout(() => this.filterAdBluePlantsByTechnology(), 0);
downer
  • 27
  • 1
  • 9
0

Here is an approach that works - conditionally set the hidden attribute on <agm-map>:

[attr.hidden]="loading ? true : null"

Stackblitz: https://stackblitz.com/edit/angular-google-maps-agm-map-xbhve9?file=app%2Fapp.component.html

wlf
  • 3,086
  • 1
  • 19
  • 29
  • I have updated the stackblitz to use a ` – wlf Feb 17 '22 at 01:44
  • yeah, this works better than assigning the class name, but it still needs the timeout... thanks for your answer! – downer Feb 17 '22 at 14:22
  • You shouldn't need the timeout - there is no timeout in my Stackblitz example. – wlf Feb 17 '22 at 21:54
  • My map has an agm-marker, and it uses this waypoints object. I had to add a timeout to the filtering method of that object to make it work. – downer Feb 19 '22 at 12:39