Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open Pop Up on Click Outside of Map

I have a list, and through clicking on the list Elements, I want to open the pop up on the marker. Currently, the pop up only opens when the marker is clicked.

This is how I create the marker and the pop ups

import React from 'react';
import {
  CircleMarker,
  Popup,
} from 'react-leaflet';

class PointsLayer extends React.Component {
  render() {
    const { data } = this.props;
    return (
      data.map(point => {
        return (
          <CircleMarker
            key={point.id}
            center={point.coordinates}>
            <Popup>
              Fancy Pop Up
            </Popup>
          </CircleMarker>
        )
      })
    )
  }

and

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
  Map,
} from 'react-leaflet';
import L from 'leaflet';
import PointsList from './PointsList;
import PointsLayer from './PointsLayer;

class Map extends React.Component {

componentDidMount() {
    this.map = this.mapInstance.leafletElement;
}

render() {
  const { data } = this.props;
  return (
    <>
      <Map
        ref={e => { this.mapInstance = e }}}>
        <TileLayer
          url=..." />
        <PointsLayer
           data={data} />
       </Map>
       <PointsList
         data={data} />
     </>
   )
 }

}

Each data point from data is a marker on the <Map /> through the <PointsLayer /> component, and a listentry in <PointsList />. I want to open the pop up in <PointsLayer /> when the corrresponding entry in <PointsList /> is clicked.

How would I do that?

like image 731
Stophface Avatar asked Jun 17 '19 14:06

Stophface


1 Answers

To open Popup Marker.openPopup() method could be utilized. The following component demonstrates how to access native Marker object in react-leaflet library and open Popup:

function MarkerExample(props) {
  const markerRef = useRef(null);
  const { center, content, openPopup } = props;

  useEffect(() => {
    markerRef.current.leafletElement.openPopup();
  }, []);

  return (
    <CircleMarker ref={markerRef} center={center}>
      <Popup>{content}</Popup>
    </CircleMarker>
  );
}

Here is a list of changes for your example:

a)introduce a separate component for a marker which accepts a openPopup prop to determine whether Popup needs to be opened or not:

function PointMarker(props) {
  const markerRef = useRef(null);
  const { center, content, openPopup } = props;

  useEffect(() => {
    if (openPopup) markerRef.current.leafletElement.openPopup();
  }, [openPopup]);

  return (
    <CircleMarker ref={markerRef} center={center}>
      <Popup>{content}</Popup>
    </CircleMarker>
  );
}

b)modify PointsList component to transfer the index of selected item via event handler, like this:

function PointsList(props) {
  const { data, onItemClick } = props;
  return (
    <div>
      <ul>
        {data.map((item, index) => (
          <li
            key={index}
            onClick={e => {
              onItemClick(index);
            }}
          >
            {item.name}
          </li>
        ))}
      </ul>
    </div>
  );
}

c)And finally in a map component introduce the index of selected marker as state variable. Now once external element is clicked, update selected index to get Popup opened:

function MapExample(props) {
  const [selected, setSelected] = useState();
  const { zoom, center, locations } = props;

  function handleItemClick(index) {
    setSelected(index);
  }

  return (
    <div>
      <PointsList data={locations} onItemClick={handleItemClick} />
      <Map center={center} zoom={zoom}>
        <TileLayer url="https://{s}.tile.osm.org/{z}/{x}/{y}.png" />
        <PointsLayer selectedIndex={selected} data={locations}  />
      </Map>
    </div>
  );
}

Here is a demo

like image 170
Vadim Gremyachev Avatar answered Oct 18 '22 01:10

Vadim Gremyachev