yagajs / leaflet-ng2

Angular.io integration of Leaflet
https://leaflet-ng2.yagajs.org
ISC License
66 stars 26 forks source link

Adding markers at runtime #387

Closed jochenjonc closed 6 years ago

jochenjonc commented 6 years ago

Hi,

I've noticed that alle examples are without backend code, almost everything is defined in html. But for the project I'm working on I want to add a few hundred markers from code.

I already have a working sample, but I'm not sure it is coded correctly. For instance I'm using the Leaflet Marker and FeatureGroup instead of classes from the Yaga module. Is this the way to go?

Also I'm struggling with events that are fired outside of Angular's Zone and I see that the examples have no problem with that. Is this because I'm using the Leaflet classes instead of the Yaga classes? Or how is the zone problem handled with leaflet-ng2.

Below you can find a snippet of my code.

    const TruckMarker = L.Marker.extend({
      options: {
        truckId: ''
      }
    });

    const truckGroup = new L.FeatureGroup();

    for (let i = 0; i < trucks.length; i++) {
      const truck = trucks[i];

      const truckMarker = new TruckMarker(L.latLng([truck[2] as number, truck[3] as number]), {
        truckId: truck[0],
        icon: L.icon({
          iconSize: [25, 41],
          iconAnchor: [13, 41],
          iconUrl: 'assets/images/marker-icon.png',
          shadowUrl: 'assets/images/marker-shadow.png'
        })
      });
      truckMarker.bindPopup(truck[1] as string);
      truckMarker.addTo(truckGroup);
    }

    truckGroup.addTo(this.map);
    truckGroup.on('click', this.truckClicked);

    this.map.fitBounds(truckGroup.getBounds());
  }

  private truckClicked(event): void {
    // PROBLEM: Leaflet event handlers run outside of Angular's zone
    this.truckId = event.layer.options.truckId;
  }

Is it possible to help me in the right direction? Or maybe add an example on how to manipulate leaflet map via Yaga?

Thx,

Jochen

atd-schubert commented 6 years ago

You use the module in the "old JavaScript way" and not with the advantage of Angular.

At first you have to create a controller that also includes your data, something like that:

@Component({ /* ... */ })
export class AppComponent implements AfterContentInit {
    @ViewChild(MapComponent) private mapComponent: MapComponent;
    @ViewChild(FeatureGroupDirective) private featureGroupDirective: FeatureGroupDirective;

    public trucks: YourTypeForATruck[] = [ /* prefer getting this data over a provider! */ ];
    public currentTruckId: string | undefined;

    public ngAfterContentInit(): void {
        this.mapComponent.fitBounds(featureGroupDirective.getBounds());
    }
    public doSomethingOnClick(event: LeafletMouseEvent, truck: YourTypeForATruck) {
        this.currentTruckId = truck.id;
        // ...
    }
}

Then you can write your simple template in HTML.

<yaga-map>
  <yaga-feature-group #truckGroup>
    <yaga-marker *ngFor="let truck of trucks"
      [lat]="truck.lat"
      [lng]="truck.lng"
      (click)="doSomethingOnClick($event, truck)"
    >
      <yaga-popup>{{ truck.contentToDisplayInPopup }}</yaga-popup>
      <yaga-icon
        [iconSize]="..."
        [iconAnchor]="..."
        [iconUrl]="..."
        [shadowUrl]="..."
      ></yaga-icon>
    </yaga-marker>
  </yaga-feature-group>
<yaga-map>
atd-schubert commented 6 years ago

In addition - according to the issue title:

When you now want to add a truck, you just have to do something like:

this.trucks.push({ /* your new truck data... */ });

For live data prefer Observables!

jochenjonc commented 6 years ago

@atd-schubert thanks for the quick response. I had a face-palm moment when seeing the solution. I was on the wrong track because I was also looking at the leafletjs documentation at the same time.

It's just an idea, but a more real-world example will probably help others to.