Как открыть соответствующее информационное окно маркера при нажатии на элемент списка

У меня есть список элементов местоположения (в виде элементов <li>), которые я хочу привязать к маркерам карты, чтобы при нажатии элемента <li> открывалось соответствующее информационное окно. Вот код:

/* This import the static locations .js file for the default markers */
import { StaticLocations } from "./StaticLocations";

let map;
let markers = [];

class App extends Component {
state = {
  locations: StaticLocations,
  map: {},
  filterQuery: "",
  mapInitialization: true,
  infowindowOpen: false,
  venuesList: [],
  foundVenues: [],
  hamburgerToggled: false,  // Set initial hamburger menu state
};

Эта функция инициализирует карту и объекты карты.

initMap() {
const initialCenter = new window.google.maps.LatLng( 45.438384, 10.991622 );
let mapOptions = {
  zoom: 14,
  center:  initialCenter,
  styles: MapStyles,
  mapTypeId: window.google.maps.MapTypeId.ROADMAP
};

/* Create map */
map = new window.google.maps.Map(document.getElementById( "map" ), mapOptions);

/* Create infowindow */
const largeInfoWindow = new window.google.maps.InfoWindow({
  maxWidth: 350
});

/* Loop through the locations array and create a marker for each coordinates */
for ( let i = 0; i < locations.length; i++ ) {
  const position = locations[i].locationCoords;
  const locationTitle = locations[i].locationName;

  const newMarker = new window.google.maps.Marker({
    map: map,
    position: position,
    title: locationTitle,
    animation: window.google.maps.Animation.DROP,
    icon: markerIcon,
    id: i
  });

  /* Push the newly created markers to the markers array */
  markers.push( newMarker );

  /* Listen for a click event to open the corresponding infowindow */
  newMarker.addListener("click", () => {
    this.populateInfoWindow( newMarker, largeInfoWindow );
  });

  /* Close infowindow when the map is clicked on */
  this.onMapClicked ( largeInfoWindow );

  /* Extend the map boundaries to include the markers */
  bounds.extend( markers[i].position );
}   
// Extend the boundaries of the map for each marker
map.fitBounds (bounds );
}

/* Create infowindow content and link it to the corresponding marker */
populateInfoWindow( marker, infowindow ) {
let infoWindowContent = `<div id="info-window">
                            <h3>${marker.title}</h3>
                            <p>Description here</p>
                         </div>`;
if ( infowindow.marker !== marker ) {
  infowindow.marker = marker;
  infowindow.setContent( infoWindowContent );
  infowindow.open( map, marker );
  }
}

render() {

/* Destructure state variables for readability */
const { hamburgerToggled, foundVenues, locations } = this.state;

return (

  <div id="app-container" role="main">

    {/* Display an error message if there was a probolem with the API call */}
    <div id="display-error-field"></div>

     {/* Header component */}
     <Header />

      <main className="main-map">

      {/* Side menu */} 
      <aside className = { hamburgerToggled ? "hamburger-show" : "hamburger-hide" }>

        <div id="list-wrapper">

          {/* Input component */}
          <FilterLocations 
          />

Ниже приведен список местоположений, которые я хочу связать с маркерами: когда я нажимаю на элементы списка местоположений, карта должна фокусироваться на соответствующем маркере и открывать информационное окно.

          <ul id="list-aside">
            { locations.map(( location, index ) => {
              return (
              <li 
                key = { index }
                onClick = { () => alert( "clicked on " + location.locationName ) }
                >{ location.locationName }</li>
              );
            })};
          </ul>
        </div>
      </aside>

    {/* Map component */}
    <section className="map-container">
      <Map />

    </section>
   </main>
  </div>
 );
}

Ps .: Вот файл StaticLocations, координаты которого выбираются для отображения маркеров по умолчанию:

export const StaticLocations = [{
locationCoords: {
  lat: 45.42422,
  lng: 10.991686
},
locationName: "Mizuki Lounge Restaurant",
locationId: "5952389dccad6b171c8d3e58",
address: "",
},
{
locationCoords: {
  lat: 45.448458542692556,
  lng: 11.00220835305019
},
locationName: "TeodoricoRe Restaurant Bar Verona",
locationId: "4dcee64f45ddbe15f8956f72",
address: ""
},
{
locationCoords: {
  lat: 45.438385,
  lng: 10.991622
},
locationName: "Hotel Montemezzi Restaurant",
locationId: "59c1f834a2a6ce4762f1de1e",
address: ""
},
{
locationCoords: {
  lat: 45.44499306798319,
  lng: 10.998014420366752
},
locationName: "AMO Opera Restaurant",
locationId: "52630778498ef9cb50326fb7",
address: ""
},
{
locationCoords: {
  lat: 45.44232305284876,
  lng: 10.99606990814209
},
locationName: "Sun Restaurant",
locationId: "5590d1da498e4edbe573034b",
address: ""
}
];

Надеюсь, мне удалось прояснить свою проблему. Если нет, и если вы думаете, что этот вопрос можно улучшить, проголосуйте против, но, пожалуйста, я имею в виду, пожалуйста, предоставьте конструктивный комментарий: это платформа для обучения, и я хотел бы терпеть меня, учиться, даже из моих собственных ошибок. Спасибо :)


person Bruno Mazza    schedule 12.08.2018    source источник


Ответы (1)


Касательно

когда я нажимаю на элементы списка локаций, карта должна фокусироваться на соответствующем маркере и открывать информационное окно.

вы можете рассмотреть следующий список изменений:

a) введите selectedItem, чтобы сохранить выбранный элемент списка в состоянии компонента и обновить его один раз после нажатия li:

  state = {
    selectedItem: null
  }

  showInfo(e, id) {
    let result = data.find(item => {
      return item.locationId === id;
    });
    this.setState({ "selectedItem": result });
  }

б) передать значение selectedItem как prop в компонент Map для отображения информационного окна:

render() {
    return (
      <div>
        <ul>
          {data.map((item, index) => {
            return <li key={index} onClick={e => this.showInfo(e, item.locationId)}>{item.locationName}</li>;
          })}
        </ul>

          <Map center={{ lat: 45.438384, lng: 10.991622 }} zoom={14} data={data} selectedItem={this.state.selectedItem} />
      </div>
    );
  }

в) в компоненте Map найдите соответствующий маркер для каждого выбранного элемента и отобразите информационное окно:

componentDidUpdate() {
    if (this.props.selectedItem) {
        //1. find selecter marker object
        let selectedMarker = this.markers.find(m => {
            return m.id === this.props.selectedItem.locationId;
        });
        //2.show info window goes here...
    }
}

Демо

person Vadim Gremyachev    schedule 13.08.2018
comment
Привет, Вадим, твое решение кажется абсолютно разумным, и спасибо за помощь. Однако, когда я пытаюсь запустить его, я продолжаю получать ошибку TypeError: Cannot read property 'maps' of undefined. Я поместил /* global google */ поверх файла. Любые идеи? - person Bruno Mazza; 14.08.2018
comment
Обновление: я установил пакет ReactDependentScript, и теперь он работает должным образом. Большое спасибо за помощь! - person Bruno Mazza; 14.08.2018