Search code examples
leafletangular5ngx-leaflet

geoJSON onEachFeature Mouse Event


I have a problem where i try to use the onEachFeature Methode for a geoJSON Layer. I try to assign a click listener to every Feature. The problem is that i always get that error when i click at a feature:

Uncaught TypeError: Cannot read property 'detectChanges' of undefined

I can think of that this is because the Layer is assigned before the constructor runs but to do that in the ngOnInit function wont worked either. Would be cool if ther is a good way to do that :)

  constructor(private changeDetector: ChangeDetectorRef){}

  fitBounds: LatLngBounds;
  geoLayer = geoJSON(statesData, {onEachFeature : this.onEachFeature});

  onEachFeature(feature , layer) {
    layer.on('click', <LeafletMouseEvent> (e) => {
        this.fitBounds = [
            [0.712, -74.227],
            [0.774, -74.125]
        ];
        this.changeDetector.detectChanges();
    });
  }

  layer: Layer[] = [];
  fitBounds: LatLngBounds;
  
  onEachFeature(feature , layer : geoJSON) {
    layer.on('click', <LeafletMouseEvent> (e) => {
        console.log("tets"+e.target.getBounds().toBBoxString());
        this.fitBounds = [
            [0.712, -74.227],
            [0.774, -74.125]
        ];
        this.changeDetector.detectChanges();
    });
  }
  
constructor(private changeDetector: ChangeDetectorRef){}

ngOnInit() {
      let geoLayer = geoJSON(statesData, {onEachFeature : this.onEachFeature});
      this.layer.push(geoLayer);
}


Solution

  • You need to make sure that the right this is accessible in your callback. You do this using function.bind() in Javascript. See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

    constructor(private changeDetector: ChangeDetectorRef){}
    
    fitBounds: LatLngBounds;
    geoLayer = geoJSON(statesData, {
        // Need to bind the proper this context
        onEachFeature : this.onEachFeature.bind(this)
    });
    
    onEachFeature(feature , layer) {
      // 'this' will now refer to your component's context
      let that = this;
    
      layer.on('click', <LeafletMouseEvent> (e) => {
          that.fitBounds = [
              [0.712, -74.227],
              [0.774, -74.125]
          ];
    
          // Aliased 'that' to refer to 'this' so it is in scope
          that.changeDetector.detectChanges();
      });
    
    }
    

    The let that = this trick is to make sure you don't have the same problem on the click event handler. But, you could also make that handler be a function in your class and use bind to set this.