React-google-maps: React Google Map InfoWindow showing all the info when I click on a single Mark

Created on 19 Jan 2018  Â·  20Comments  Â·  Source: tomchentw/react-google-maps

Hi all,

I am having an issue with making the InfoWindow shows up for the Mark I click on.
The expect behavior is when I click on the mark it will only shows information about that mark in the InfoWindow.

However, What I am getting now is that when I click on a marker all the marker shows up. And when I tried to close it rerender the app.

Any Idea how to fix this?

  class VenuesMap extends Component {

constructor(props){
    super(props);

    this.state = {
        zoom: 11,
        isOpen: false
    }

handleToggle = () => {
    this.setState({
        isOpen: !false
    });
}
  render() {

        markers = venues.map((location, i) => {

            const lat = location.venue.location.lat
            const lng = location.venue.location.lng
            const index = i + 1 ;
            return (
                <Marker
                    key={i}
                    position={{ lat: lat, lng: lng}}
                    label={index.toString()}
                    onClick={this.handleToggle}
                >
                {this.state.isOpen &&
                <InfoWindow
                        onCloseClick={this.handleToggle}
                        >
                    <span>Something</span>
                </InfoWindow>
             }
            </Marker>
            )
        })

  const MapWithAMarker = withGoogleMap(props =>
     <GoogleMap
      defaultZoom={this.state.zoom}
       defaultCenter={{ lat:Number(latCurrentLocation) || 40.7128, lng: 
      Number(lngCurrentLocation) || -74.0060}}

           >
    {markers}
    {userMarkers}
      </GoogleMap>
   );

    const googleMap =   <MapWithAMarker
        containerElement={<div style={{ height: this.props.containerElement }} />}
        mapElement={<div style={{ height: this.props.mapElement}}  />}
    />

        return (
        <div>
            {googleMap}
        </div>
    )
      }
   }

 export default connect(stateToProps)(VenuesMap)

screen shot 2018-01-18 at 11 53 01 pm
screen shot 2018-01-18 at 11 53 14 pm

Most helpful comment

my solution below
try this:

{props.nhatro.map((nhatro, index) =>
        <Marker
          key={index}
          options={{icon: 'https://i.imgur.com/9G5JOp8.png'}}
          position={nhatro}
          onClick={()=>{ props.showInfo(index)} }
        >
          { (props.showInfoIndex == index ) && 
          <InfoWindow  onCloseClick={props.onToggleOpen}>
            <div>
              <div>nhĂ  trọ cho thuĂȘ</div>
              <div >1.500.000đ</div>
            </div>
          </InfoWindow>}
        </Marker>
    )}

and then :

showInfo(a){
 setState({showInfoIndex: a })
}

All 20 comments

I fixed. I replaced with Marker and InfoWindow to its component.

import React, {Component} from 'react';
import { Marker, InfoWindow } from "react-google-maps";

class InfoWindowMap extends Component {

constructor(props){
    super(props);

    this.state = {
        isOpen: false
    }

}

handleToggleOpen = () => {

    this.setState({
        isOpen: true
    });
}

handleToggleClose = () => {
    this.setState({
        isOpen: false
    });
}

render() {

return (
        <Marker
            key={this.props.index}
            position={{ lat: this.props.lat, lng: this.props.lng}}
            label={this.props.index.toString()}
            onClick={() => this.handleToggleOpen()}
        >

        {
            this.state.isOpen &&
         <InfoWindow onCloseClick={this.props.handleCloseCall}>
             <h1>{this.props.location.venue.name}</h1>
         </InfoWindow>
        }


        </Marker>

    )

}
}

export default InfoWindowMap;

Hi @spaceforestchu - is this the complete code for the fix? I tried to replicate your fix but couldn't seem to do it. Is there a separate component for GoogleMap? If so, can you post your entire fix?

Thanks for posting the solution!

@hrashid sorry I just saw this.
I made an info window component.
lat: this.props.lat,
lng: this.props.lng
}} label={this.props.index.toString()}
onClick={() => this.handleClicks(this.props.venueID)}
>

        {
          this.state.isOpen &&

                    <InfoWindow onCloseClick={() => this.setState({isOpen: false})}>
              <div>
                <h4>{this.props.location.venue.name}</h4>
                <img src={`${venuePhoto}`}/>
                <span>{number}</span>
              </div>
            </InfoWindow>

        }

      </Marker>

then I put the infoWindowMap component in sindei google map component.

    <InfoWindowMap
                        key={index}
                        lat={lat}
                        lng={lng}
                        index={index}
                        location={location}
                        indexValue={index}
                        venueID={venueID}

                        />

You can find the code in my github the project is called your 4 square. Let me know if you need any help.

I have same problem and I solved like following..

class GoogleMapBox extends React.Component{
    state = {
        position : null
    }

    handleToggleOpen(item){
        this.setState({
            position : {
                lat : item.lat,
                lng : item.lng
            }           
        })
    }

    render(){
        return (
            <GoogleMap ....>
                {markers.map((item) => (
                    <Marker
                        key={this.props.index}
                        position={{ lat: this.props.lat, lng: this.props.lng}}
                        label={this.props.index.toString()}
                        onClick={() => this.handleToggleOpen(item)}
                    />
                )}


                {this.state.position && 
                     <InfoWindow position={this.state.position}>
                         <h1>{this.props.location.venue.name}</h1>
                     </InfoWindow>
                 }
            </GoogleMap>
        )
    }   
}

(this code is not exact. cause I quickly typed it in this editor)
this way is isn't in .

It works good. I recommend this way.

my solution below
try this:

{props.nhatro.map((nhatro, index) =>
        <Marker
          key={index}
          options={{icon: 'https://i.imgur.com/9G5JOp8.png'}}
          position={nhatro}
          onClick={()=>{ props.showInfo(index)} }
        >
          { (props.showInfoIndex == index ) && 
          <InfoWindow  onCloseClick={props.onToggleOpen}>
            <div>
              <div>nhĂ  trọ cho thuĂȘ</div>
              <div >1.500.000đ</div>
            </div>
          </InfoWindow>}
        </Marker>
    )}

and then :

showInfo(a){
 setState({showInfoIndex: a })
}

@nguyenvanphuc2203 where did you put your ShowInfo ?

image

@nguyenvanphuc2203 Thanks for your code. However, after opening an info window and closing it once. The info window will not be able to show up again.

So below is the quick fix, I just added an additional condition for showing the info window (ie . props.isOpen).

      {locationMarkers && locationMarkers.map((marker) =>
        <Marker key={marker.index} position={marker.position} onClick={() => { props.showInfo(marker.index) }}>
          {(props.isOpen && props.showInfoIndex == marker.index) &&
            <InfoWindow onCloseClick={props.onToggleOpen}>
              <div>
                {marker.info}
              </div>
            </InfoWindow>}
        </Marker>
      )}

If there is another better fix, please let me know!

nice man :D

@nguyenvanphuc2203 @pttse
IMO, the easiest and the right way is to 'reset' showInfo prop on close.
BTW, you could use only one function that handles opening and closing InfoWindow.
My code looks like this:

withStateHandlers(() => ({
  isOpen: false,
  infoIndex: null
}), {
  showInfo: ({ isOpen, infoIndex }) => (index) => ({
    isOpen: infoIndex !== index || !isOpen,
    infoIndex: index
  })
})
<Marker onClick={() => props.showInfo(marker.index)}>
  {(props.isOpen && props.infoIndex === marker.index) &&
    <InfoWindow onCloseClick={props.showInfo}>
      <span>{marker.info}</span>
    </InfoWindow>}
</Marker>

**Hi guys!
Can someone help me?

I have this error: **
image

in the following peace of code:

import React from 'react'
import PropTypes from 'prop-types'

import template from 'modules/template'
import OverlayView from './CustomOverlayView'

import IconButton from '@material-ui/core/IconButton';
import Place from '@material-ui/icons/Place'

import blueGrey from '@material-ui/core/colors/blueGrey';
import red from '@material-ui/core/colors/red';

import { getColors } from 'utils/status'

import PersonalizedInfoWindow from './PersonalizedInfoWindow'

const disabledColor = blueGrey[500]

const DefaultIcon = ({
status,
isEnabled = true,
isSelected = false,
...other
}) => {
const { primary = red[500] } = getColors(status)
let color = (!isEnabled && !isSelected) ? disabledColor : primary
const iconStyle = { color }
return
}

class CustomOverlayMarker extends React.Component {

constructor(props) {
super(props)

this.state = {
  isOpen: false
}

}

handleMouseOver = () => {
this.setState({
isOpen: true
})
}

handleMouseOver = () => {
this.setState({
isOpen: false
})
}

render() {

let markerIcon
if (this.props.children) {
  markerIcon = React.cloneElement(this.props.children, this.props.size)
} else {
  markerIcon = <DefaultIcon {...this.props} />
}

let infoWindow = null
if (this.state.isOpen) {
  infoWindow = <PersonalizedInfoWindow position={this.props.position} label={this.props.label} />
}

// For some reason the general provider is not inherited in the OverlayView :-S
const MuiThemeProvider = template.components.ThemeProvider

return (
  <OverlayView
    mapPaneName={OverlayView.OVERLAY_MOUSE_TARGET}
    position={this.props.position}
    getPixelPositionOffset={() => ({ x: -this.props.size / 2, y: -this.props.size })}
  >
    <MuiThemeProvider>
      <IconButton
        tooltip={this.props.label}
        onClick={this.props.onClick}
        onMouseOver={this.handleMouseOver()}
        onMouseOut={this.handleMouseOver()}
      >
        {markerIcon}
        {infoWindow}
      </IconButton>

    </MuiThemeProvider>

  </OverlayView>
)

}

}

CustomOverlayMarker.propTypes = {
size: PropTypes.number,
label: PropTypes.string,
position: PropTypes.object,
isEnabled: PropTypes.bool,
isSelected: PropTypes.bool,
onClick: PropTypes.func
}

export default CustomOverlayMarker

Does someone know how to avoid this??

```
handleMouseOver = () => {
if (!this.state.isOpen) {
this.setState({
isOpen: true
})
}
}

handleMouseOver = () => {
if (this.state.isOpen) {
this.setState({
isOpen: false
})
}
}
```

The solution was as simple as adding this:


tooltip={this.props.label}
onClick={this.props.onClick}
onMouseOver={()=>this.handleMouseOver()}
onMouseOut={()=>this.handleMouseOver()}
>

My solution:

withStateHandlers(() => ({
    isOpen: false,
    markerIndex: 0
  }), {
    onToggleOpen: ({ isOpen }) => (index) => ({
      isOpen: !isOpen,
      markerIndex: index
    })
  })


<Marker
onClick={ ()=> {props.onToggleOpen(index} }>
{ props.isOpen && props.markerIndex === index &&
              <InfoWindow onCloseClick={props.onToggleOpen}>
                <div>Working</div>
              </InfoWindow>
}
</Marker>

The infoWindow corresponding to the marker doesn't get shown up when i click on the marker. The markers keep refreshing when i click on them. I can't figure out what i've done wrong. Can anybody help me with this ?

import { GoogleApiWrapper, Map, Marker, InfoWindow } from "google-maps-react";
import React, { useState } from "react";
import { GOOGLE_API_KEY } from "../../../../../utils/environment";
import styles from "./../../../wrappers/widgetsWrapper.module.scss";

const mapStyles = {
  width: "100%",
  height: "100%"
};

const GoogleMaps = props => {
  const [infoOpen, setInfoOpen] = useState(null);

  const { chartData } = props;

  const handleToggle = (id) => {
    setInfoOpen(id)
  }

  const formatData = (chartData) => {
    chartData.map((place, index) => {
      place.id = "id" + index
    })
    const data = chartData
    return data
  }
  // const mapDetails = formatData(chartData.data.mapData)
  // console.log("mapDetails : ", mapDetails);
  const mapDetails = [
    {
      "label": "Lady Gray Gourmet Medibles",
      "lat": 61.217835,
      "lng": -149.88037
    },
    {
      "label": "Lady Gray Gourmet Medibles",
      "lat": 64.837205,
      "lng": -147.806626
    },
    {
      "label": "Glacier Extracts",
      "lat": 64.837205,
      "lng": -147.806626
    },
    {
      "label": "Baked Alaska",
      "lat": 61.191401,
      "lng": -149.912576
    },
  ]

  return (
    <React.Fragment>
      <div className={styles.dashboardWidgetCard}>
        <Map
          google={props.google}
          zoom={4}
          style={mapStyles}
          initialCenter={{ lat: 61.217835, lng: -149.88037 }}
        >
          {mapDetails.map((mapData, index) => (
            <Marker
              key={index}
              position={{ lat: mapData.lat, lng: mapData.lng }}
              onClick={() => { handleToggle(index) }}
            >
              {(infoOpen == index) &&
                <InfoWindow>
                  <h3>helooo</h3
                </InfoWindow>
              }

            </Marker>
          ))}
        </Map>
      </div>
    </React.Fragment>
  );
};

export default GoogleApiWrapper({
  apiKey: GOOGLE_API_KEY
})(GoogleMaps);

@SenelithPerera
The repo of this project is unmaintained more than a year, and we had build new version https://www.npmjs.com/package/@react-google-maps/api

We had rewrite it to TypeScript, and updating it frequently: https://github.com/JustFly1984/react-google-maps-api/tree/master/packages/react-google-maps-api
You can enjoy autocomplete.

You can see our docs: https://react-google-maps-api-docs.netlify.com/

Also a lot of examples: https://react-google-maps-api-gatsby-demo.netlify.com/ https://github.com/JustFly1984/react-google-maps-api/tree/master/packages/react-google-maps-api-gatsby-example/src/examples

The bundle size is much smaller: https://bundlephobia.com/result?p=@react-google-maps/api@1.7.5

Enjoy!

@JustFly1984 Just after posting this question, I found your github repo. The issue was fixed.

@nguyenvanphuc2203 Thanks for your code. However, after opening an info window and closing it once. The info window will not be able to show up again.

So below is the quick fix, I just added an additional condition for showing the info window (ie . props.isOpen).

      {locationMarkers && locationMarkers.map((marker) =>
        <Marker key={marker.index} position={marker.position} onClick={() => { props.showInfo(marker.index) }}>
          {(props.isOpen && props.showInfoIndex == marker.index) &&
            <InfoWindow onCloseClick={props.onToggleOpen}>
              <div>
                {marker.info}
              </div>
            </InfoWindow>}
        </Marker>
      )}

If there is another better fix, please let me know!

Could you please share the all the code. I am trying with this but getting some issues

@mahendragurav2
The repo of this project is unmaintained more than a year, and we had build new version https://www.npmjs.com/package/@react-google-maps/api

We had rewrite it to TypeScript, and updating it frequently: https://github.com/JustFly1984/react-google-maps-api/tree/master/packages/react-google-maps-api
You can enjoy autocomplete.

You can see our docs: https://react-google-maps-api-docs.netlify.com/

Also a lot of examples: https://react-google-maps-api-gatsby-demo.netlify.com/ https://github.com/JustFly1984/react-google-maps-api/tree/master/packages/react-google-maps-api-gatsby-example/src/examples

The bundle size is much smaller: https://bundlephobia.com/result?p=@react-google-maps/api@1.7.7

Our Spectrum community: https://spectrum.chat/react-google-maps

Enjoy!

Here is a complete solution InfoWindow shows. i have also attached the link you can see for more understanding.. https://codesandbox.io/s/quizzical-hermann-5ehs7

import React, { Component } from "react";
import { Map, InfoWindow, Marker, GoogleApiWrapper } from "google-maps-react";

export class MapContainer extends Component {
  state = {
    activeMarker: {},
    selectedPlace: {},
    showingInfoWindow: false
  };

  onMarkerClick = (props, marker) =>
    this.setState({
      activeMarker: marker,
      selectedPlace: props,
      showingInfoWindow: true
    });

  onInfoWindowClose = () =>
    this.setState({
      activeMarker: null,
      showingInfoWindow: false
    });

  onMapClicked = () => {
    if (this.state.showingInfoWindow)
      this.setState({
        activeMarker: null,
        showingInfoWindow: false
      });
  };

  render() {
    if (!this.props.loaded) return <div>Loading...</div>;

    return (
      <Map
        className="map"
        google={this.props.google}
        onClick={this.onMapClicked}
        style={{ height: "100%", position: "relative", width: "100%" }}
        zoom={13}
      >
        <Marker
          name="Marker 1"
          onClick={this.onMarkerClick}
          position={{ lat: 37.778519, lng: -122.40564 }}
        />

        <Marker
          name="Marker 2"
          onClick={this.onMarkerClick}
          position={{ lat: 37.759703, lng: -122.428093 }}
        />

        <Marker name="Marker 3" onClick={this.onMarkerClick} />

        <InfoWindow
          marker={this.state.activeMarker}
          onClose={this.onInfoWindowClose}
          visible={this.state.showingInfoWindow}
        >
          <div>
            <h4>{this.state.selectedPlace.name}</h4>
          </div>
        </InfoWindow>
      </Map>
    );
  }
}
export default GoogleApiWrapper({
  apiKey: "",
  version: "3.38"
})(MapContainer);

enter image description here

Was this page helpful?
0 / 5 - 0 ratings

Related issues

madbean picture madbean  Â·  3Comments

johnantoni picture johnantoni  Â·  3Comments

MrSaints picture MrSaints  Â·  3Comments

craigcartmell picture craigcartmell  Â·  4Comments

ShintaroNippon picture ShintaroNippon  Â·  3Comments