I have a React-Leaflet map which I am rendering a div
inside.
For some reason, interacting with the contents of the div causes the map beneath to respond (eg: double-clicking will zoom the map, dragging will pan the map) - even when I'm calling e.stopPropagation()
in handlers attached to the div.
As I understand it, calling stopPropagation()
should prevent the DOM events from ever reaching the map itself.
Why does it appear that stopPropagation()
is being ignored?
How can I render a div inside the map without it's events bubbling to the map itself?
Here is an example codepen showing the problem.
import { Map, TileLayer } from 'react-leaflet';
const MyMap = props => (
<Map zoom={13} center={[51.505, -0.09]}>
<TileLayer url={"http://{s}.tile.osm.org/{z}/{x}/{y}.png"} />
{/*
HOW do I get this div to NOT pass it's events down to the map?!?!
Why does e.stopPropagation() appear to not work?
*/}
<div
id="zone"
onClick={e => e.stopPropagation()}
onMouseDown={e => e.stopPropagation()}
onMouseUp={e => e.stopPropagation()}
>
<p>Double-click or click and drag inside this square</p>
<p>Why does the map zoom/pan?</p>
</div>
</Map>
);
ReactDOM.render(<MyMap />, document.getElementById('root'));
React: stopPropagation We extended one of the previous examples by using the stopPropagation() method on an event. This way, when the button gets clicked, the event does not bubble up and does not trigger the event handler of the surrounding container element.
To stop an event from further propagation in the capturing and bubbling phases, you call the Event. stopPropation() method in the event handler. Note that the event. stopPropagation() method doesn't stop any default behaviors of the element e.g., link click, checkbox checked.
Leaflet and its React counterpart, React Leaflet, are a fantastic open source and free mapping alternative to Google Maps and MapBox, no API key required! It is an easy package to work with and one worth trying out.
Event bubbling is a method of event propagation in the HTML DOM API when an event is in an element inside another element, and both elements have registered a handle to that event. It is a process that starts with the element that triggered the event and then bubbles up to the containing elements in the hierarchy.
For Leaflet map use L.DomEvent.disableClickPropagation
instead which:
Adds
stopPropagation
to the element's'click'
,'doubleclick'
,'mousedown'
and'touchstart'
events.
Example
function MyMap() {
return (
<div>
<Map zoom={13} center={[51.505, -0.09]}>
<TileLayer url={"http://{s}.tile.osm.org/{z}/{x}/{y}.png"} />
<MyInfo />
</Map>
</div>
);
}
where
function MyInfo() {
const divRef = useRef(null);
useEffect(() => {
L.DomEvent.disableClickPropagation(divRef.current);
});
return (
<div ref={divRef} id="zone">
<p>Double-click or click and drag inside this square</p>
<p>Why does the map zoom/pan?</p>
</div>
);
}
Updated codepen
Alternative option
Another option to stop div element from propagation to map events would be to place div outside of the map element:
<div>
<Map zoom={13} center={[51.505, -0.09]}>
<TileLayer url={"http://{s}.tile.osm.org/{z}/{x}/{y}.png"} />
</Map>
<MyInfo />
</div>
where
function MyInfo() {
return (
<div id="zone">
<p>Double-click or click and drag inside this square</p>
<p>Why does the map zoom/pan?</p>
</div>
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With