A variation on this tutorial: https://leafletjs.com/examples/choropleth/. I am attempting to add custom info control.
let info = L.control();
function highlightFeature(e) {
...
info.update(layer.feature.properties);
}
function resetHighlight(e) {
...
info.update();
}
function updateFunction(tab, props) {
this._div.innerHTML = '<h4>US Active Covid-19 Cases </h4>' + (props ?
'<b>' + props.name + '</b><br />' + getActive(tab, props.name) + ' cases'
: 'Hover over a state');
}
info.onAdd = function(map) {
this._div = L.DomUtil.create("div", "info");
this.update();
return this._div;
}
let statedata = fetch(url + stateurl).then(data => data.json());
statedata.then((data) => {
info.update = (props) => updateFunction(data, props);
let style = (feature) => styleMap(data, feature);
info.addTo(mymap);
geojson = L.geoJson(statesData, {style : style, onEachFeature: onEachFeature}).addTo(mymap);
});
Here, my info.update
is slightly different from the tutorials. info.update
and style
depend on the json data that I am only able to access inside the asynchronous section on the bottom. However, this code gives me the following error: Uncaught (in promise) TypeError: Cannot set property 'innerHTML' of undefined
, referring to the this._div
line of the updateFunction.
I found that if I do either of the following
let info = L.control()
and all of my functions that depend on info
inside the promise orinfo.update
outside of the promise,then the code will work without error. However, option 1 appears hideous and morally incorrect, and option 2 necessitates that I abandon hope of accessing the statedata json. Also, in option 2, I don't understand what difference it makes declaring info.update
inside or outside the promise. In particular, why declaring info.update inside the promise leads to undefined behavior with info._div
and declaring info.update
outside the promise does not?
Any clues as to what is wrong here would be greatly appreciated!
In the tutorial you're working from, this is what they have for info.update
:
info.update = function (props) {
this._div.innerHTML = '<h4>US Population Density</h4>' + (props ?
'<b>' + props.name + '</b><br />' + props.density + ' people / mi<sup>2</sup>'
: 'Hover over a state');
};
In this function, this
will refer to the info
object. In your code you refactor to this:
function updateFunction(tab, props) {
this._div.innerHTML = '<h4>US Active Covid-19 Cases </h4>' + (props ?
'<b>' + props.name + '</b><br />' + getActive(tab, props.name) + ' cases'
: 'Hover over a state');
}
// ...
info.update = (props) => updateFunction(data, props);
By using an arrow function that invokes a regular function, you've effectively cut the ties between info
and this
. In your case, this
is probably defaulting to window
, which would explain why _div
is undefined.
To fix this you need to explicitly bind this
to info
. You could do this:
info.update = (props) => updateFunction.bind(info)(data, props);
Or even more concise, you can simply bind this
and the first argument, and skip the arrow function intermediate altogether:
info.update = updateFunction.bind(info, data);