Leaflet- marker click event works fine but methods of the class are undefined in the callback function
This is a classic JavaScript mistake.
this
in JavaScript does not necessarily refer to your class instance object. It is the context of the function when it is called.
You can force this context with bind
, and in many libraries you can easily force it as well. In this case with Leaflet you can pass a 3rd argument to on
when attaching your event listener:
// Force current `this` to be the context when `this.markerClick` is called
marker.on('click', this.markerClick, this);
With bind
it would be:marker.on('click', this.markerClick.bind(this));
And there is also the arrow function solution, which uses the context / value of this
where the arrow function is defined, rather than where it will be called:marker.on('click', (event) => this.markerClick(event));
Angular 8 Leaflet put marker onclick
The problem is that you are using an anonymous function and in it's scope the this
keyword doesn't reference to the leaflet map
instance. You can avoid this by using an arrow function instead of the classic ES5 anonymous function beacause there are no binding of this
in arrow functions.
private selectLocation() {
this.map.on('click', (e) => {
var coord = e.latlng;
var lat = coord.lat;
var lng = coord.lng;
console.log('You clicked the map at latitude: ' + lat + ' and longitude: ' + lng);
var mp = new L.Marker([lat, lng]).addTo(this.map);
alert(mp.getLatLng());
});
}
Using Prototypal Pattern with Creating a Leaflet Map: error with onEachFeature function
Much probably simply need to bind the this
context when you pass your onEachFeature
method as argument of your IIFE to build the callback to your AJAX call:
this.onEachFeature.bind(this)
See also Leaflet- marker click event works fine but methods of the class are undefined in the callback functionBTW you could also attach your click event listener directly on the Leaflet GeoJSON Layer Group instead of doing it for each child layer.
Leaflet cant display div when mouseover marker
Doing a quick search in Leaflet's source code will show that the only place that _controlCorners
is accessed is at this line of code:
// @method addTo(map: Map): this
// Adds the control to the given map.
addTo: function (map) {
// [stuff]
var corner = map._controlCorners[pos];
// [stuff]
},
It seems that you're adding a control to a non-initialized map, or otherwise the parameter to the addTo()
call is not a map. I suggest you start by console.log()
ing the value of map
in your calls to addTo(map)
. geoJSON onEachFeature Mouse Event
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
. Uncaught TypeError: Cannot read property 'lat' of undefined Leaflet and VueJS
Your onClick
listener is called on Vue's @click="onClick"
attribute of your DOM map container. Therefore it receives a plain "click"
event, which does not have the Leaflet's latlng
added property.
Since you want to do something on the map and not directly on its container, then you probably meant to listen to Leaflet's map "click"
event. In that case, you can simply attach your listener with:
this.map.on('click', onClick, this);
(you can attach it typically just after you initialize your map)Note that it will greatly help you binding the this
context by using the 3rd argument of Leaflet's on
, otherwise this
in your listener will refer to something else than your Vue component instance (see Leaflet- marker click event works fine but methods of the class are undefined in the callback function)
How can I create an ionic popover from a leafletjs polygon?
In your case you have a double context issue since you also pass your onEachFeature
method that will get invoked with a this
context that is already different from your class instance.
You could do onEachFeature: this.onEachFeature.bind(this)
together with your layer.on("click", cb, this)
You could also use event delegation by attaching the listener on your GeoJSON Layer Group instead of each individual feature, so that you get rid of one of the context:
var geoJsonData = { "type": "Point", "coordinates": [2.35, 48.86]};
class Component { constructor(mapId) { this.myMap = L.map(mapId).setView([48.86, 2.35], 11);
L.geoJSON(geoJsonData).addTo(this.myMap).on("click", event => { console.log(event.target); // this is the GeoJSON Layer Group. console.log(event.layer); // this is the individual child feature. let popover = this.popoverCtrl.create('MyComponent'); popover.present(); }, this); // Not even needing the 3rd arg since you use a fat arrow function, which does not have its own context.
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' }).addTo(this.myMap); }}
Component.prototype.popoverCtrl = { // Dummy popoverCtrl create(content) { dummyPopoverContent = content; return { present() { alert(dummyPopoverContent); }, }; },};
var dummyPopoverContent = '';
new Component('map');
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" /><script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>
<div id="map" style="height: 180px"></div>
Related Topics
How to Auto-Slide the Window Out from Behind Keyboard When Textinput Has Focus
Rendering to Js with Jinja Produces Invalid Number Rather Than String
Keep Bootstrap Dropdown Open When Clicked Off
Adding Csrftoken to Ajax Request
Why Does JavaScript's Regex.Exec() Not Always Return the Same Value
Is Localstorage.Getitem('Item') Better Than Localstorage.Item or Localstorage['Item']
How to Send Authorization Header with Axios
Ecmascript 2015: Const in for Loops
Printing a Web Page Using Just Url and Without Opening New Window
Bootstrap: Open Another Modal in Modal
Why Is 'This' Undefined Inside Class Method When Using Promises
What Is the JavaScript Mime Type for the Type Attribute of a Script Tag
Sampling a Random Subset from an Array
How to Set Node_Env to Production/Development in Os X