Titxo
Titxo

Reputation: 73

Popup always open in the marker

Is there any way the popup always stays open and does not need to click on it to open?

Upvotes: 7

Views: 22636

Answers (7)

pavlinsky
pavlinsky

Reputation: 21

You can open the popup once the marker is added to the map:

import { Marker, Popup } from "react-leaflet";

function MyMarker() {
    const position = [41.0, 2.11];

    function openPopup(e) {
        e.target.openPopup();
    }

    return (
        <Marker position={position} eventHandlers={{ add: openPopup }}>
            <Popup closeButton={false} autoClose={false} closeOnClick={false}>
                {/* Content of your popup... */}
            </Popup>
        </Marker>
    )
}

This will additionally prevent the popup from closing. Works with react-leaflet 4.2.1.

Upvotes: 2

Marin Spudić
Marin Spudić

Reputation: 41

For the new react-leaflet v4 you will need to do some changes

   const CustomMarker = ({ isActive, data, map }) => {
                  const [refReady, setRefReady] = useState(false);
                  let popupRef = useRef();
                
                  useEffect(() => {
                    if (refReady && isActive) {
                      map.openPopup(popupRef);
                    }
                  }, [isActive, refReady, map]);
                
                  return (
                    <Marker position={data.position}>
                      <Popup
                        ref={(r) => {
                          popupRef = r;
                          setRefReady(true);
                        }}
                      >
                        {data.title}
                      </Popup>
                    </Marker>
                  );
                };

And then use MapContainer like this

const MapComponent = () => {
  const [map, setMap] = useState(null);
  return (
    <div>
      <MapContainer
        ref={setMap}
        center={[45.34416, 15.49005]}
        zoom={15}
        scrollWheelZoom={true}
      >
        <CustomMarker
          isActive
          map={map}
          data={{
            position: [45.34416, 15.49005],
            title: "Text displayed in popup",
          }}
        />
      </MapContainer>
    </div>
  );
};

Upvotes: 1

Disco
Disco

Reputation: 1634

Edited

Notice that my old solution would try to open the popup every time it renders. Found another solution that fit my needs to open it when the position changed. Notice that I look at position.lat, position.lng since it will think it always changes if you pass on the object.

And yes it is not perfect typescript but it is the best solution I could come up with.

const CustomMarker: React.FC<CustomMarkerProps> = ({ position, children }) => {
  const map = useMap();

  const markerRef = useRef(null);

  useEffect(() => {
    try {
      // @ts-ignore
      if (markerRef.current !== null && !markerRef.current.isPopupOpen()) {
        // @ts-ignore
        markerRef.current.openPopup();
      }
    } catch (error) {}
  }, [position.lat, position.lng]);

  return (
    <Marker ref={markerRef} position={position}>
      <Popup>{children}</Popup>
    </Marker>
  );
};

export default CustomMarker;

Old solution

Could not get it to work using useRef and useEffect. However, got it to work with calling openPopup() directly from the ref.

import { LatLngLiteral, Marker as LMarker } from "leaflet";
import React from "react";
import { Marker } from "react-leaflet";

export interface CustomMarkerProps {
  position: LatLngLiteral;
  open?: boolean;
}
const CustomMarker: React.FC<CustomMarkerProps> = ({
  position,
  open = false,
  children,
}) => {
  const initMarker = (ref: LMarker<any> | null) => {
    if (ref && open) {
      ref.openPopup();
    }
  };

  return (
    <Marker ref={initMarker} position={position}>
      {children}
    </Marker>
  );
};

export default CustomMarker;

Upvotes: 0

JohnG
JohnG

Reputation: 71

The above no longer works with react-leaflet version 3. In your custom marker component, to get a reference to the leaflet element you should now use useRef() and then open up the popup in useEffect() once the component is mounted.

const MyMarker = (props) => {
  const leafletRef = useRef();
  useEffect(() => {
    leafletRef.current.openPopup();
  },[])
  return <Marker ref={leafletRef} {...props} />
}

Upvotes: 4

Vadim Gremyachev
Vadim Gremyachev

Reputation: 59328

With the introduction of react-leaflet version 2 which brings breaking changes in regard of creating custom components, it is no longer supported to extend components via inheritance (refer this thread for a more details)

In fact React official documentation also recommends to use composition instead of inheritance:

At Facebook, we use React in thousands of components, and we haven’t found any use cases where we would recommend creating component inheritance hierarchies.

Props and composition give you all the flexibility you need to customize a component’s look and behavior in an explicit and safe way. Remember that components may accept arbitrary props, including primitive values, React elements, or functions.

The following example demonstrates how to extend marker component in order to keep popup open once the marker is displayed:

const MyMarker = props => {

  const initMarker = ref => {
    if (ref) {
      ref.leafletElement.openPopup()
    }
  }

  return <Marker ref={initMarker} {...props}/>
}

Explanation:

get access to native leaflet marker object (leafletElement) and open popup via Marker.openPopup method

Here is a demo

Upvotes: 20

Simon Hutchison
Simon Hutchison

Reputation: 3035

You can use permanent tooltips, or React provides refs for this type of thing... you can do this:

https://jsfiddle.net/jrcoq72t/121/

const React = window.React
const { Map, TileLayer, Marker, Popup } = window.ReactLeaflet

class SimpleExample extends React.Component {
  constructor () {
    super()
    this.state = {
      lat: 51.505,
      lng: -0.09,
      zoom: 13
    }
  }

  openPopup (marker) {
    if (marker && marker.leafletElement) {
      window.setTimeout(() => {
        marker.leafletElement.openPopup()
      })
    }
  }

  render () {
    const position = [this.state.lat, this.state.lng]
    return (
      <Map center={position} zoom={this.state.zoom}>
        <TileLayer attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="http://{s}.tile.osm.org/{z}/{x}/{y}.png" />
        <Marker position={position} ref={this.openPopup}>
          <Popup>
            <span>
              A pretty CSS3 popup. <br /> Easily customizable.
            </span>
          </Popup>
        </Marker>
      </Map>
    )
  }
}

window.ReactDOM.render(<SimpleExample />, document.getElementById('container'))

References:

https://reactjs.org/docs/refs-and-the-dom.html

React.js - access to component methods

Auto open markers popup on react-leaflet map

Upvotes: 4

Per Fr&#246;jd
Per Fr&#246;jd

Reputation: 162

What you can do is to make your own Marker class from the react-leaflet marker, and then call the leaflet function openPopup() on the leaflet object after it has been mounted.

// Create your own class, extending from the Marker class.
class ExtendedMarker extends Marker {
    componentDidMount() {
        // Call the Marker class componentDidMount (to make sure everything behaves as normal)
        super.componentDidMount();

       // Access the marker element and open the popup.
      this.leafletElement.openPopup();
    }
}

This will make the popup open once the component has been mounted, and will also behave like a normal popup afterwards, ie. on close/open.

I threw together this fiddle that shows the same code together with the basic example.

Upvotes: 13

Related Questions