How can I disable or change the href on a React-Leaflet v4 Popup close button?
Asked Answered
H

5

8

In react-leaflet v4, the Popup component has a default href associated with the close button that directs to #close. Is there a way in React to modify this href or disable the href redirection? It's breaking my react-dom HashRouter.

Of note, Popup.js in Leaflet 1.8 has the following code:

var closeButton = this._closeButton = DomUtil.create('a', prefix + '-close-button', container);
closeButton.setAttribute('role', 'button'); // overrides the implicit role=link of <a> elements #7399
closeButton.setAttribute('aria-label', 'Close popup');
closeButton.href = '#close';
closeButton.innerHTML = '<span aria-hidden="true">&#215;</span>';
Hint answered 26/4, 2022 at 21:36 Comment(1)
This is a known bug in Leaflet 1.8 and will be resolved with the release of Leaflet 1.9: github.com/Leaflet/Leaflet/issues/8356Midland
A
3

The same issue is also in angular - means it seems to be the leaflet Lib:

    // leaflet.js
    close: function () {
        if (this._map) {
            this._map.removeLayer(this);
        }
        return this;
    },

The close function has not even the $event as an argument and the "default" isn't prevented. This leaves us only dirty hacks:

  1. Get the close button after the marker was displayed
  2. Add a click handler more
  3. Add a prefentDefault
  yourMethodOpensTheToolTip(marker: Marker) {
    if (marker && marker.openPopup) {
      marker.openPopup();
      // 1. get the close buttons, after the opened the popup
      const closeButtons = document.getElementsByClassName('leaflet-popup-close-button');
      // 2. add the event handler - if you have more than one, loop here
      if (closeButtons && closeButtons.length > 0) {
        L.DomEvent.on(closeButtons[0] as HTMLElement, 'click', function(ev){
          ev.preventDefault(); // 3. stop it here
        });
      }

Just for reference the #close button as HTML: #close a tag

Acropolis answered 2/6, 2022 at 13:20 Comment(0)
S
1

Try something like this. It will probably disable any other hrefs that you may have in the popup though.

document.querySelector('.leaflet-pane.leaflet-popup-pane')!.addEventListener('click', event => {
        event.preventDefault();
});
Solute answered 12/5, 2022 at 21:2 Comment(1)
This is great, using this in Angular. Small error: '.leaflet-pane.leaflet-popup-pane' must be '.leaflet-pane .leaflet-popup-pane'. Note the spaceTrocar
S
0

You can utilize useRef hooks and create a click event in the marker

const mapRef = useRef(null);

// event listener to handle marker click
const handleClick = () => {
    mapRef.current._popup._closeButton.addEventListener('click', (event) => {
     event.preventDefault();
    })
};

const map = (<MapContainer center={position} zoom={13} scrollWheelZoom={false} style={{ height: '350px', width: '100%' }} ref={mapRef}>
    <TileLayer
      attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
      url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
    />
    <Marker
      position={position}
      eventHandlers={{
        click: (e) => handleClick(),
      }}
    >
      <Popup>
        A pretty CSS3 popup. <br /> Easily customizable.
      </Popup>
    </Marker>
  </MapContainer>)

if you are using GeoJSON you can use onEachFeature props

const onEachCountry = (country, layer) => {
const countryName = country.properties.ADMIN;
layer.on('click', function (e) {
  layer
    .bindPopup(countryName)
    .openPopup()
    ._popup._closeButton.addEventListener('click', (event) => {
      event.preventDefault();
    });
}); 
};

const map = (<MapContainer style={{ height: '300px' }} zoom={1} center={[20, 100]}>
    <GeoJSON style={countryStyle} data={mapData.features} onEachFeature={onEachCountry} />
  </MapContainer>)
Sn answered 20/5, 2022 at 16:26 Comment(1)
I could'nt make work. _closeButton is undefined when the handleClick is run :( (it's defined later)Carbarn
C
0

In my React project with react-leaflet v4, I had the same issue and I solved it with the "popupopen" event :

https://leafletjs.com/reference.html#marker-popupopen

<Marker
    position={position}
    eventHandlers={{
        popupopen: (e) => {
            e.popup._closeButton.removeAttribute("href");
            e.popup._closeButton.style.cursor = "pointer";
        }
    }}
>
    <Popup>
        <p>Lorem ipsum dolor sit amet</p>
    </Popup>
</Marker>

I hope it will help.

Cathleencathlene answered 8/9, 2022 at 14:50 Comment(0)
W
0

Building on Paul's answer. Here is the solution if you have multiple popups. This will handle the close button click event on all the popups that are open on the leaflet map.

    // This is a stopgap till Leaflet fixes its issue with close buttons in popups in Leaflet maps
      let popupCloseButtonsHTMLCollection =  document.getElementsByClassName('leaflet-popup-close-button');
      if(popupCloseButtonsHTMLCollection && popupCloseButtonsHTMLCollection.length > 0){
        //convert the popupCloseButtonsHTMLCollection to array 
        var popupArray = [].slice.call(popupCloseButtonsHTMLCollection);
        popupArray.forEach(button =>{
          L.DomEvent.on(button as HTMLElement, 'click', function(ev){
            ev.preventDefault(); 
          });
        });

      }
Winshell answered 10/2, 2023 at 19:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.