2

I've set up my application using angular5 with ngx-leaflet (https://github.com/Asymmetrik/ngx-leaflet).

I start with a blank map. When a user clicks a button, markers appear on the map. When a user selects a marker, that marker is identified to a country and that country is linked with other countries based on some other (non-important) data.

<div id="map-sidebar">
    <div class="map-buttons-bar">
        <button class="btn btn-primary" (click)="addLayer()">Set Marker</button>
    </div>
</div> 

In my .ts file, I have

addLayer(){
    var n_marker = marker([38.9072, -77.0369], {icon: this.anomalyIcon});
    n_marker.on('click', (e)=>{             
        this.mapToPartnerCountries();
    })
    this.lLayers.push(n_marker);
  }

mapToPartnerCountries(){

    var n_marker = marker([39.9072, -78.0369], {icon: this.anomalyIcon});
    this.lLayers.push(n_marker); 
    //var newLayer = geoJSON(geo as any);
    //this.lLayers.push(newLayer);
  }

My issue is the new layer does not appear when the mapToPartnerCountries() method is run. But if I click the button again, it appears. GeoJson does the same thing as well. Am I doing this the correct way?

Also the this.lLayers field is used in the map element...

<div class="map-container" 
            leaflet 
            [leafletOptions]="mapOptions" 
            [leafletLayersControl]="layersControl"
            [leafletLayers]="lLayers"
        >
Keith James
  • 167
  • 1
  • 12

1 Answers1

0

Angular uses zones to determine what events do and do not trigger change detection. Any event that is propagated from a template (e.g., the (click) event) will trigger change detection unless you specifically configure it not to. That is why when you click again, the changes are applied.

Leaflet events are intentionally set up to happen outside of the Angular zone (for various reasons, but mostly performance related). You can read more here. Angular won't detect any changes made to component properties if the changes are made outside of the Angular zone.

You are modifying this.lLayers inside of a callback on a Marker click event, which is likely occurring outside of Angular's zone. To get Angular to "see" this modification, you will need to perform it inside of Angular's zone using NgZone.run().

For example:

constructor(private zone: NgZone) {}

addLayer(){
   var n_marker = marker([38.9072, -77.0369], {icon: this.anomalyIcon});
   n_marker.on('click', (e) => {

      this.zone.run(() => {         
         this.mapToPartnerCountries();
      });

   })
   this.lLayers.push(n_marker);
}

That code will ensure that this.mapToPartnerCountries(); is run inside of Angular's zone so that change detection will be performed.

reblace
  • 4,115
  • 16
  • 16
  • This worked perfectly. So my final question is, am I adding the layers in a recommended fashion or is there a better way? – Keith James Apr 18 '18 at 18:08
  • How you are managing layers is correct. ngx-leaflet supports mutating the bound layers array. It uses a custom to detect mutation changes (similar to ngFor). The issue you ran into is purely because of the Angular zones and the events coming directly out of Leaflet. Which is a pretty complicated topic. But, once you see what's going on, it's easy to deal with. – reblace Apr 19 '18 at 11:51