I have a list component displaying objects with accordion elements.
On expanding the accordion body, I use a (click)="addToArray(id)"
method and have <edit-component *ngIf="idArray.includes(id)"></edit-component>
in the accordion body.
The reason is to load the edit-component
after expansion of the accordion, because it includes a leaflet map that didn't display properly when the accordion was collapsed initially.
Now, the edit-component
includes some inputs and methods for handling and validating those, as well as a map-input-component
. It's using Leaflet, and I had to put the .map-container
in the edit-component
template because it couldn't find the DOM element in it's own component..
I want this map component to emit where the user is clicking on the map, and have gotten as far as reading the leaflet event and wanting to emit it with an @Output
to the edit-component
parent.
However, when I try to access the this.mapClickEvent
it's undefined.
I suspect this might be because the component is loaded on runtime?
Is my only option to include the map directly in the edit-component
instead?
edit.component.ts
@Component({
selector: "edit-component",
templateUrl: "./edit.component.html"
})
export class EditComponent {
@Input() myObject!: myObjectInterface;
// Methods for other inputs
onMapClick(event: {lat: number, lng: number}){
console.log(event)
}
}
edit.component.html
<div class="row">
<!-- Other cols with inputs -->
<div class="col">
<div class="map-container" [attr.id]="'map-input-' + myObject.id"></div>
<map-input-component
[object]="myObject"
(mapClickEvent)="onMapClick($event)"
></map-input-component>
</div>
</div>
map-input.component.ts
@Component({
selector: "map-input-component",
template: "",
standalone: true
})
export class MapInputComponent {
@Input() object!: myObjectInterface;
@Output() mapClickEvent = new EventEmitter<{lat: number, lng: number}>();
// Leaflet map setup with L.on("click", this.onMapClick)
onMapClick(e: LeafletMouseEvent) {
// A console.log(e) logs the wanted data
// A console.log(this.mapClickEvent) logs undefined
this.mapClickEvent.emit({lat: e.latlng.lat, lng: e.latlng.lng});
}
}
Error
ERROR TypeError: Cannot read properties of undefined (reading 'emit')
at NewClass.onMapClick (map-input.component.ts:132:24)
at NewClass.fire (leaflet-src.js:606:11)
at NewClass._fireDOMEvent (leaflet-src.js:4565:17)
at NewClass._handleDOMEvent (leaflet-src.js:4514:10)
at HTMLDivElement.handler (leaflet-src.js:2799:15)
at _ZoneDelegate.invokeTask (zone.js:398:33)
at core.mjs:14556:55
at AsyncStackTaggingZoneSpec.onInvokeTask (core.mjs:14556:36)
at _ZoneDelegate.invokeTask (zone.js:397:38)
at Object.onInvokeTask (core.mjs:14869:33)
When you set the mapClickEvent
to Leafset, make sure to bind
it to the scope of the component, you can do this by using .bind(this)
.
Wherever the function executes it will always have the scope of the component.
L.on("click", this.onMapClick.bind(this))
As per code shared, it should be:
const leafletMap: Map = map(mapContainer).on("click", this.onMapClick.bind(this));