Google Maps API, Marker onClick listener not working as intended - google-maps

right now I'm trying to build a map that shows all the hospitals in Indonesia (and later on about covid cases) and so far I've been able to successfully grab locations from a json file and map it onto a map. My map has a button such that if you click it all the hospitals in Indonesia will show up on the map as markers. What I want to do now is to have an InfoWindow pop-up of the hospital name when a user clicks on a specific marker.
How I tried to approach it:
Create a state boolean array for all hospital markers to see if the hospital has been clicked
If the hospital has been clicked, output an InfoWindow with the Hospitals name.
Issue:
It seems that when I click the button to show all hospitals in Indonesia, it updates the state boolean array to all true. I'm not sure why that is the case, and when I click on a specific marker the state array is unchanged.
This is my git repo if you need the full code: https://github.com/ktanojo17505/google-map-react
Here is my state:
state = {
address: "",
city: "",
area: "",
state: "",
zoom: 11,
height: 400,
mapPosition: {
lat: 0,
lng: 0
},
markerPosition: {
lat: 0,
lng: 0
},
placeHospitals: false,
Hospitals: [],
didClickHospital: []
};
This is my constructor:
constructor(props) {
super(props);
var HospitalLocations = [];
var clickHospital = [];
var position;
var hospitalName;
var id;
for (let index = 0; index < HospitalData.hospitals.length; ++index) {
id = index;
var latitude = HospitalData.hospitals[index].latitude;
var longitude = HospitalData.hospitals[index].longitude;
position = { latitude, longitude };
hospitalName = HospitalData.hospitals[index].nama;
var entry = { id, position, hospitalName };
HospitalLocations.push(entry);
clickHospital.push(false);
}
this.state.Hospitals = HospitalLocations;
this.state.didClickHospital = clickHospital;
}
This is my return
return (
<div style={{ padding: "1rem", margin: "0 auto", maxWidth: 1000 }}>
<h1>Google Maps Basic</h1>
<Descriptions bordered>
<Descriptions.Item label="City">{this.state.city}</Descriptions.Item>
<Descriptions.Item label="Area">{this.state.area}</Descriptions.Item>
<Descriptions.Item label="State">
{this.state.state}
</Descriptions.Item>
<Descriptions.Item label="Address">
{this.state.address}
</Descriptions.Item>
</Descriptions>
<MapWithAMarker
googleMapURL={
"https://maps.googleapis.com/maps/api/js?key=" +
config.GOOGLE_API_KEY +
"&v=3.exp&libraries=geometry,drawing,places"
}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
<div style={{ marginTop: "2.5rem" }}>
<Button onClick={this.placeHospitals}>Hospitals</Button>
</div>
</div>
);
MapwithMarker
const MapWithAMarker = withScriptjs(
withGoogleMap(props => (
<div>
<GoogleMap
defaultZoom={this.state.zoom}
defaultCenter={{
lat: this.state.mapPosition.lat,
lng: this.state.mapPosition.lng
}}
options={options}
onClick={this.placeMarker}
>
<Marker
draggable={true}
onDragEnd={this.onMarkerDragEnd}
position={{
lat: this.state.markerPosition.lat,
lng: this.state.markerPosition.lng
}}
>
<InfoWindow>
<div>{this.state.address}</div>
</InfoWindow>
</Marker>
{this.state.placeHospitals &&
this.state.Hospitals.map(hospitalLoc => ( // Place the locations if Hospitals Button is clicked
<Marker
draggable={false}
position={{
lat: hospitalLoc.position.latitude,
lng: hospitalLoc.position.longitude
}}
key={hospitalLoc.id}
onClick={this.clickHospital(hospitalLoc.id)} // Change the state of the Hospital InfoWindow
>
{/* {this.state.didClickHospital[index] && ( // If true output an infowindow of the hospital name
<InfoWindow>
<div>{hospitalLoc.name}</div>
</InfoWindow>
)} */}
</Marker>
))}
<AutoComplete
style={{
width: "100%",
height: "40px",
paddingLeft: 16,
marginTop: 2,
marginBottom: "2rem"
}}
types={["(regions)"]}
onPlaceSelected={this.onPlaceSelected}
/>
</GoogleMap>
</div>
))
);
clickHospital
clickHospital = id => {
console.log("clicked");
// var tempClickHospital = this.state.didClickHospital;
// console.log(tempClickHospital[index]);
// tempClickHospital[index] = !tempClickHospital[index];
// console.log(tempClickHospital[index]);
// this.setState({ didClickHospital: tempClickHospital });
// console.log(this.state.didClickHospital);
};
This is the output of my code (before clicking Hospitals)1
This is the output of my code (after clicking Hospitals)2
If anyone could point out what I'm doing wrong that would be helpful thank you!

You can directly map each data from the json file to create an individual <Marker> with <InfoWindow> inside it.
Here's a working sample code and the code snippet below on how to do this:
import React, { Component } from "react";
import {
withGoogleMap,
GoogleMap,
Marker,
InfoWindow
} from "react-google-maps";
//import the json data of your hospital info
import data from "./data.json";
import "./style.css";
class Map extends Component {
constructor(props) {
super(props);
this.state = {
hospitalId: "",
addMarkerBtn: false
};
}
addMarkerFunction = () => {
this.setState({
addMarkerBtn: true
});
};
handleToggleOpen = id => {
this.setState({
hospitalId: id
});
};
render() {
const GoogleMapExample = withGoogleMap(props => (
<GoogleMap
defaultCenter={{ lat: -6.208763, lng: 106.845599 }}
defaultZoom={16}
>
{this.state.addMarkerBtn === true &&
data.map(hospital => (
<Marker
key={hospital.id}
position={{ lat: hospital.lat, lng: hospital.lng }}
onClick={() => this.handleToggleOpen(hospital.id)}
>
{this.state.hospitalId === hospital.id && (
<InfoWindow
onCloseClick={this.props.handleCloseCall}
options={{ maxWidth: 100 }}
>
<span>{hospital.id}</span>
</InfoWindow>
)}
</Marker>
))}
</GoogleMap>
));
return (
<div>
<button id="addMarker" onClick={() => this.addMarkerFunction()}>
Add Marker
</button>
<GoogleMapExample
containerElement={<div style={{ height: `500px`, width: "500px" }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
}
export default Map;

Related

How do I get my route to show up on my map with React Google Maps?

I've successfully been able to render the Markers for react-google-maps, but when I started trying to use DirectionsRenderer, I ran into this 'google is not defined' issue. I scoured StackOverflow and the web in general for solutions to this, anywhere from declaring 'google' as a global to playing around with the withScriptjs syntax, and nothing has worked. I'm running out of ideas. Sidenote: I'm deliberately avoiding using the 'recompose' library from the docs because even the library's author thinks Hooks are better...so idk, maybe give me a solution that doesn't require 'recompose' if possible? Thanks a million.
Here's my code:
/* global google */
import React, { useState, useEffect } from 'react'
import { withGoogleMap, GoogleMap, Marker, DirectionsRenderer } from 'react-google-maps'
import './App.css'
function MyDirectionsRenderer(props) {
const [directions, setDirections] = useState(null);
const { origin, destination, travelMode } = props;
useEffect(() => {
const directionsService = new google.maps.DirectionsService();
directionsService.route(
{
origin: new google.maps.LatLng(origin.lat, origin.lng),
destination: new google.maps.LatLng(destination.lat, destination.lng),
travelMode: travelMode
},
(result, status) => {
if (status === google.maps.DirectionsStatus.OK) {
setDirections(result);
} else {
console.error(`error fetching directions ${result}`);
}
}
);
}, [directions, destination.lat, destination.lng, origin.lat, origin.lng, travelMode]);
return (
<React.Fragment>
{directions && <DirectionsRenderer directions={directions} />}
</React.Fragment>
);
}
class Map extends React.Component {
constructor(props){
super(props);
this.state = {
directions: null
}
}
render(){
const MyMapComponent = withGoogleMap(props => {
return (
<GoogleMap
defaultZoom={10}
defaultCenter={{ lat: 42.681340, lng: -89.026930 }}
>
<Marker
position = {{lat: 42.681340, lng: -89.026930}}
/>
<MyDirectionsRenderer
origin= {{lat: 42.681339, lng: -89.026932}}
destination= {{lat: 28.250200, lng: -82.714080}}
travelMode= {google.maps.TravelMode.DRIVING}
/>
</GoogleMap>
)
})
return (
<MyMapComponent
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
)
}
}
export default Map
Edit: I updated the code here to reflect the current status of the project and any existing problems with it. Currently, the problem is that I can't see the route on my map.
Since ESLint is not aware that the variable google is a global, you can declare a variable you referenced as a global by adding the following to the top of your file:
/* global google */
then the error 'google' is not defined should disappear.
And last but not least, the instance of google.maps.DirectionsService could be created only once the Google Maps APIs is loaded. The following example demonstrates how to accomplish it:
<GoogleMap
defaultZoom={4}
defaultCenter={{ lat: 27.71415, lng: -82.3583 }}
>
<MyDirectionsRenderer
origin={{ lat: 27.71415, lng: -82.3583 }}
destination={{ lat: 42.681339, lng: -89.026932 }}
travelMode={google.maps.TravelMode.DRIVING}
/>
</GoogleMap>
where
function MyDirectionsRenderer(props) {
const [directions, setDirections] = useState(null);
const { origin, destination, travelMode } = props;
useEffect(() => {
const directionsService = new google.maps.DirectionsService();
directionsService.route(
{
origin: new google.maps.LatLng(origin.lat, origin.lng),
destination: new google.maps.LatLng(destination.lat, destination.lng),
travelMode: travelMode
},
(result, status) => {
if (status === google.maps.DirectionsStatus.OK) {
setDirections(result);
} else {
console.error(`error fetching directions ${result}`);
}
}
);
}, [directions]);
return (
<React.Fragment>
{directions && <DirectionsRenderer directions={directions} />}
</React.Fragment>
);
}

How to create Polyline using react-google-maps library

I am trying to plot Polyline between 4 GPS coordinates using react-google-maps library. Nothing is rendering on the map
import React from 'react';
import { withGoogleMap, GoogleMap, Marker, InfoWindow,Polyline } from 'react-google-maps';
class googleMapComponent extends React.Component {
//Higher order components: withGoogleMap is employed as a function call. This fucntion returns another component defination which is later mounted in render
// maintain a refernce to a map inside the component, so that
constructor(){
super()
this.state ={
map:null
}
}
mapMoved(){
console.log('mapMoved: ' + JSON.stringify(this.state.map.getCenter()))
}
mapLoaded(map){
//console.log('mapLoaded: ' + JSON.stringify(map.getCenter()))
if(this.state.map !==null)
return
this.setState({
map:map
})
}
zoomchanged(){
console.log('mapZoomed: ' + JSON.stringify(this.state.map.getZoom()))
}
handleMarkerClick(targetMarker) {
this.setState({
markers: this.state.markers.map(marker => {
if (marker === targetMarker) {
return {
...marker,
showInfo: true,
};
}
return marker;
}),
});
}
handleMarkerClose(targetMarker) {
this.setState({
markers: this.state.markers.map(marker => {
if (marker === targetMarker) {
return {
...marker,
showInfo: false,
};
}
return marker;
}),
});
}
render() {
const markers= [
{
position: new google.maps.LatLng(36.05298766, -112.0837566),
showInfo: false,
infoContent: false,
},
{
position: new google.maps.LatLng(36.21698848, -112.0567275),
showInfo: false,
infoContent: false,
},
]
const lineCoordinates= [
{coordinate: new google.maps.LatLng(36.05298766, -112.0837566)},
{coordinate: new google.maps.LatLng(36.0529832169413, -112.083731889724)},
{coordinate: new google.maps.LatLng(36.0529811214655, -112.083720741793)},
{coordinate: new google.maps.LatLng(36.0529811214655, -112.083720741793)},
]
return (
<GoogleMap
ref={this.mapLoaded.bind(this)}
onDragEnd={this.mapMoved.bind(this)}
onZoomChanged={this.zoomchanged.bind(this)}
defaultZoom={this.props.zoom}
defaultCenter={this.props.center}
>
{markers.map((marker, index) => (
<Marker
position={marker.position}
title="click on it Sir..!!"
defaultPosition={this.props.center}
style={{height: '2xpx', width: '2px'}}
/>
))}
{lineCoordinates.map((polyline,index)=>(
<Polyline
defaultPosition={this.props.center}
path= {polyline.coordinate}
geodesic= {true}
strokeColor= {#FF0000}
strokeOpacity= {1.0}
strokeWeight= {2}
/>
</GoogleMap>
)
}
}
export default withGoogleMap(googleMapComponent);
Any suggestion on it will be helpful. If the library does not support this functionality. I can swtich the library too.
Yes. Example:
render() {
const pathCoordinates = [
{ lat: 36.05298765935, lng: -112.083756616339 },
{ lat: 36.2169884797185, lng: -112.056727493181 }
];
return (
<GoogleMap
defaultZoom={this.props.zoom}
defaultCenter={this.props.center}
>
{/*for creating path with the updated coordinates*/}
<Polyline
path={pathCoordinates}
geodesic={true}
options={{
strokeColor: "#ff2527",
strokeOpacity: 0.75,
strokeWeight: 2,
icons: [
{
icon: lineSymbol,
offset: "0",
repeat: "20px"
}
]
}}
/>
</GoogleMap>
);
}
When you run the mapping function, are you creating a new polyline for each set of coordinates? Looking at the Google Maps docs, the polyline takes an array of objects as a path argument. google-maps-react is just a wrapper around that API, so you should be able to create your polyline just by passing in the array of objects as the path. Currently, you're trying to generate a bunch of polyline objects based on tiny coordinate fragments.
A simpler example to show just one polyline being drawn:
<GoogleMap defaultZoom={7} defaultCenter={{ lat: -34.897, lng: 151.144 }}>
<Polyline path={[{ lat: -34.397, lng: 150.644 }, { lat: -35.397, lng: 151.644 }]}/>
</GoogleMap>
Entire snippet for anyone unclear about the correct imports and setup (with recompose):
import React from "react";
import ReactDOM from "react-dom";
import { compose, withProps } from "recompose";
import {
withScriptjs,
withGoogleMap,
GoogleMap,
Marker,
Polyline
} from "react-google-maps";
const MyMapComponent = compose(
withProps({
googleMapURL:
"https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&v=3.exp&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />
}),
withScriptjs,
withGoogleMap
)(props => (
<GoogleMap defaultZoom={7} defaultCenter={{ lat: -34.897, lng: 151.144 }}>
<Polyline path={[{ lat: -34.397, lng: 150.644 }, { lat: -35.397, lng: 151.644 }]}/>
</GoogleMap>
));
ReactDOM.render(<MyMapComponent />, document.getElementById("root"));
Same example as above, without recompose:
import React from "react";
import ReactDOM from "react-dom";
import {
withScriptjs,
withGoogleMap,
GoogleMap,
Polyline
} from "react-google-maps";
const InternalMap = props => (
<GoogleMap defaultZoom={7} defaultCenter={{ lat: -34.897, lng: 151.144 }}>
<Polyline
path={[{ lat: -34.397, lng: 150.644 }, { lat: -35.397, lng: 151.644 }]}
/>
</GoogleMap>
);
const MapHoc = withScriptjs(withGoogleMap(InternalMap));
const MyMapComponent = props => (
<MapHoc
googleMapURL="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&v=3.exp&libraries=geometry,drawing,places"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
);
ReactDOM.render(
<MyMapComponent />,
document.getElementById("root")
);

react-google-maps InfoWindow not displayed

I'm trying to open an infoWindow when I click on a marker.
I followed documentation step by step (https://tomchentw.github.io/react-google-maps/basics/pop-up-window) and even if I can pass the property showInfo to true, the pop-up won't be displayed...
import React, {Component} from "react";
import "./Map.css";
import _ from "lodash";
import {withGoogleMap, GoogleMap, Marker, Polyline, InfoWindow} from "react-google-maps";
import withScriptjs from "react-google-maps/lib/async/withScriptjs";
import mapStyle from '../assets/map_style.json';
const GettingStartedGoogleMap = withScriptjs(withGoogleMap(props => (
<GoogleMap
ref={props.onMapLoad}
defaultZoom={11}
//defaultCenter={{lat: 48.853, lng: 2.35}}
defaultCenter={{lat: 33.5731, lng: -7.5898}}
defaultOptions={{
styles: mapStyle,
zoom: 12,
minZoom: 12,
maxZoom: 18
}}
onClick={props.onMapClick}
onResize={props.onResize}
onBoundsChanged={props.onBoundsChanged}
onCenterChanged={props.onCenterChanged}
>
{props.markers.map((marker, index) => (
<Marker
{...marker}
key={marker.id}
position={marker.position}
onClick={() => props.onMarkerClick(marker)}
>
{}
{marker.showInfo && (
<InfoWindow onCloseClick={() => props.onMarkerClose(marker)}>
<div>hello</div>
</InfoWindow>
)}
</Marker>
))}
{props.polylines.map((polyline, index) => (
<Polyline
{...polyline}
key={polyline.id}
path={polyline.coords}
options={polyline.options}
onRightClick={_.noop}
/>
))}
</GoogleMap>
)));
class Map extends Component {
constructor(props) {
super(props);
this.map = null;
this.state = {
allowedBounds: null,
lastValidCenter: null
};
this.onMapLoad = this.onMapLoad.bind(this);
this.onBoundsChanged = this.onBoundsChanged.bind(this);
this.onCenterChanged = this.onCenterChanged.bind(this);
}
onMapLoad(map) {
this.map = map;
this.setState({allowedBounds: new window.google.maps.LatLngBounds(
new window.google.maps.LatLng(33.5, -7.7),
new window.google.maps.LatLng(33.65, -7.45)
)});
this.setState({lastValidCenter: this.map.getCenter()});
}
onBoundsChanged() {
this.onBoundsChanged = _.noop;
this.props.onMapReady(this.map);
}
onCenterChanged() {
if (this.state.allowedBounds == null)
return;
if (this.state.allowedBounds.contains(this.map.getCenter())) {
// still within valid bounds, so save the last valid position
this.setState({lastValidCenter: this.map.getCenter()});
return;
}
// not valid anymore => return to last valid position
this.map.panTo(this.state.lastValidCenter);
}
handleMarkerClick(targetMarker) {
console.log(this.props.markers);
this.setState({
markers: this.props.markers.map(marker => {
if (marker === targetMarker) {
marker = {
...marker,
showInfo: true,
};
console.log(marker);
}
return marker;
}),
});
}
handleMarkerClose(targetMarker) {
this.setState({
markers: this.props.markers.map(marker => {
if (marker === targetMarker) {
return {
...marker,
showInfo: false,
};
}
return marker;
}),
});
}
handleMarkerClick = this.handleMarkerClick.bind(this);
handleMarkerClose = this.handleMarkerClose.bind(this);
render() {
return (
<section id="map" className={this.props.className}>
<GettingStartedGoogleMap
containerElement={
<div style={{height: `100%`}}/>
}
mapElement={
<div style={{height: `100%`}}/>
}
loadingElement={
<p>Loading...</p>
}
googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyDGNmlXqmPTqSkJpC2DLEIaSL9X6azn2b8&libraries=places,geometry"
onMapLoad={this.onMapLoad}
onResize={() => console.log("resize")}
onMapClick={() => console.log(this.map)}
onMarkerClick={this.handleMarkerClick}
onMarkerClose={this.handleMarkerClose}
markers={this.props.markers}
polylines={this.props.polylines}
onBoundsChanged={this.onBoundsChanged}
onCenterChanged={this.onCenterChanged}
/>
</section>
);
}
}
export default Map;
So the marker returns this in my console :
Object {id: "t1_10", position: _.F, showInfo: true, icon: Object}
icon:Object
id:"t1_10"
position:_.F
showInfo:true
Thank you in advance !

React-google-maps +redux - how to center map when new location is fetched?

I am using react-google-maps and I followed that example : LINK . I am fetchng data which comes from GPS device and I would like to center when new data is fetched.
Here is code of the whole map component:
const GettingStartedGoogleMap = withGoogleMap(props => (
<GoogleMap
ref={props.onMapLoad}
defaultZoom={18}
defaultCenter={props.defCenter}
onClick={props.onMapClick}
>
{props.markers.map((marker,i) => (
<Marker
key={i}
position={marker.location}
time={marker.time}
onClick={() => props.onMarkerClick(marker)}
>
{ marker.isShown &&
<InfoWindow onCloseClick={() => props.onMarkerClick(marker)}>
<div className="marker-text">{marker.time} </div>
</InfoWindow>
}
</Marker>
))}
</GoogleMap>
));
class GettingStartedExample extends Component {
componentDidMount(){
this.props.fetchMarkers();
console.log("MONT");
console.log(this.props.markers.length);
}
componentWillReceiveProps(){
console.log(this.props.markers);
console.log(this.props.markers.length);
}
state = {
markers: this.props.markers,
center: {lat: 50.07074, lng: 19.915718},
};
handleMapLoad = this.handleMapLoad.bind(this);
handleMarkerClick = this.handleMarkerClick.bind(this);
handleMapLoad(map) {
this._mapComponent = map;
if (map) {
console.log(map.getZoom());
}
}
handleMarkerClick(targetMarker) {
/*
* All you modify is data, and the view is driven by data.
* This is so called data-driven-development. (And yes, it's now in
* web front end and even with google maps API.)
*/
const nextMarkers = this.state.markers.filter(marker => marker !== targetMarker);
if(targetMarker.isShown==true)
{
targetMarker.isShown=false;
}
else
{
targetMarker.isShown=true;
}
this.setState({
markers: nextMarkers,
center: {lat: 5.07074, lng: 19.915718}
});
}
render() {
const markers = this.props.markers.map((marker,i) => {
return (
<Marker key={i} position={marker.location} time={marker.time} onClick={this.handleMarkerClick} />
)});
var centerPos;
var lastMark;
if(markers[markers.length-1]!== undefined)
{
centerPos=markers[markers.length-1].props.position;
lastMark=markers[markers.length-1].props;
console.log(centerPos);
}
else {
centerPos={lat: 5.07074, lng: 19.915718};
}
return (
<div className='container map-container'>
<GettingStartedGoogleMap
containerElement={
<div style={{ height: `100%` }} />
}
mapElement={
<div style={{ height: `100%` }} />
}
onMapLoad={this.handleMapLoad}
markers={this.props.markers}
onMarkerClick={this.handleMarkerClick}
defCenter={this.state.center}
lastMarker={lastMark}
/>
</div>
);
}
}
GettingStartedExample.propTypes={
markers: React.PropTypes.array.isRequired,
fetchMarkers: React.PropTypes.func.isRequired
}
function mapStateToProps(state){
return{
markers:state.markers
}
}
export default connect(mapStateToProps,{fetchMarkers})(GettingStartedExample);
Probably I have to set state of center to the last object in this.props.markers, I tried to do it on componentWillReceiveProps(), but I have no idea how to that.I also tried here in render():
if(markers[markers.length-1]!== undefined)
{
centerPos=markers[markers.length-1].props.position;
lastMark=markers[markers.length-1].props;
console.log(centerPos);
}
else {
centerPos={lat: 5.07074, lng: 19.915718};
}
and tried to pass it to the state, but it didn't work. I am sure the solution is simple, but I have no experience with React.If it would be helpful I am adding code of actions.js where redux action for fetching markers is defined:
export const SET_MARKERS='SET_MARKERS';
/*markers*/
export function setMarkers(markers){
return{
type:SET_MARKERS,
markers
}
}
export function fetchMarkers(){
return dispatch => {
fetch('/api/markers')
.then(res=>res.json())
.then(data=>dispatch(setMarkers(data.markers)));
;
}
}
Just add center property to GoogleMap component.
<GoogleMap
center={props.center}
/>

React-google-maps + redux - InfoWindow on marker click

I am trying to have same effect on my page as here react-google-map demo. I used react-google-maps. The thing is I am fetching data with markers' informations and I don't know how can I handle click that will show/hide InfoWindow. Probably the reason is somewhere with state, I don't know how to make variable "isShown" true/false for each marker in markers array. Here is my code:
const GettingStartedGoogleMap = withGoogleMap(props => (
<GoogleMap
ref={props.onMapLoad}
defaultZoom={16}
defaultCenter={props.defCenter}
onClick={props.onMapClick}
>
{props.markers.map((marker,i) => (
<Marker
key={i}
position={marker.location}
time={marker.time}
onClick={() => props.onMarkerClick(marker)}
// HERE I TRIED SOMETHING LIKE marker.isShown=true; but it is NOT WORKING
>
{
<InfoWindow>
<div className="marker-text">{marker.time}</div>
</InfoWindow>
}
</Marker>
))}
</GoogleMap>
));
class GettingStartedExample extends Component {
componentDidMount(){
this.props.fetchMarkers();
}
state = {
markers: this.props.markers,
};
handleMapLoad = this.handleMapLoad.bind(this);
handleMarkerClick = this.handleMarkerClick.bind(this);
handleMapLoad(map) {
this._mapComponent = map;
if (map) {
console.log(map.getZoom());
}
}
handleMarkerClick(targetMarker) {
/*
* All you modify is data, and the view is driven by data.
* This is so called data-driven-development. (And yes, it's now in
* web front end and even with google maps API.)
*/
const nextMarkers = this.state.markers.filter(marker => marker !== targetMarker);
console.log(targetMarker.showInfo)
this.setState({
markers: nextMarkers,
});
}
render() {
return (
<div className='container map-container'>
<GettingStartedGoogleMap
containerElement={
<div style={{ height: `100%` }} />
}
mapElement={
<div style={{ height: `100%` }} />
}
onMapLoad={this.handleMapLoad}
markers={this.props.markers}
onMarkerClick={this.handleMarkerClick}
defCenter={{lat: 50.07074, lng: 19.915718}}
/>
</div>
);
}
}
GettingStartedExample.propTypes={
markers: React.PropTypes.array.isRequired,
fetchMarkers: React.PropTypes.func.isRequired
}
function mapStateToProps(state){
return{
markers:state.markers
}
}
export default connect(mapStateToProps,{fetchMarkers})(GettingStartedExample);
Currently it looks like this:
Markers with InfoWindow
On my final effect I would like to have InfoWindow on the newest marker and handle click that allows you to show/hide InfoWindows on all markers.
How can I achieve that showing/hiding InfoWindow on each marker?
Thanks a lot for any help!
you can try this
i am getting markers array in nextProps and so set it into the state
you can use your own markers array
import React from 'react'
import { Link } from 'react-router'
import { withGoogleMap, GoogleMap, Marker, InfoWindow } from 'react-google-maps'
const num10 = 10
const GettingStartedGoogleMap = withGoogleMap((props) => (
<GoogleMap
ref={props.onMapLoad}
defaultZoom={10}
center={props.center}
onClick={props.onMapClick}
>
{props.markers.map((marker, index) => (
<Marker
key={index}
position={marker.position}
onClick={() => props.onMarkerClick(marker)}
{...marker}
//onRightClick={() => props.onMarkerRightClick(index)}
>
{marker.showInfo && (
<InfoWindow onCloseClick={() => props.onMarkerClose(marker)}>
<div className="">
myinfowindow
</div>
</InfoWindow>
)}
</Marker>
))}
</GoogleMap>
))
class GoogleMaps extends React.Component {
constructor(props) {
super(props)
this.state = {
center: {
lat: 33.6890603,
lng: -78.8866943
},
markers: [],
true: true
}
}
componentWillReceiveProps(nextProps) {
this.setState({ markers: [] }, () => {
const m = nextProps.pageNo - 1
if (nextProps.markers[0] !== undefined) {
let obj = {}
let newArray = []
for (let i = m * num10; i <= nextProps.markers.length; i++) {
if (i === m * num10 + num10) { break }
obj = {
position: { lat: nextProps.markers[i].loc[1], lng: nextProps.markers[i].loc[0] },
rate: nextProps.markers[i].spaces[0].rate,
infoContent: nextProps.markers[i].listingName || nextProps.markers[i].spaces[0].name,
showInfo: false,
photos: nextProps.markers[i].photos[0],
description: nextProps.markers[i].basic_details.notes,
secured: nextProps.markers[i].isSecured,
markerIcon: false, id: nextProps.markers[i]._id
}
newArray = this.state.markers
newArray.push(obj)
this.setState({ markers: newArray,
center: { lat: nextProps.markers[0].loc[1],
lng: nextProps.markers[0].loc[0]
}
})
}
} else {
this.setState({ markers: this.props.markers })
}
})
}
handleMarkerClick(targetMarker) {
this.setState({
markers: this.state.markers.map((marker) => {
if (marker === targetMarker) {
return {
...marker,
showInfo: true,
markerIcon: true
}
} else {
return {
...marker,
showInfo: false
}
}
})
})
}
handleMarkerClose(targetMarker) {
this.setState({
markers: this.state.markers.map((marker) => {
if (marker === targetMarker) {
return {
...marker,
showInfo: false
}
}
return marker
})
})
}
handleMarkerClose2(targetMarker) {
this.setState({
markers: this.state.markers.map((marker) => {
if (targetMarker) {
return {
...marker,
showInfo: false
}
}
return marker
})
})
}
render() {
return (<div>
<div id="mapcanvas"
className="col-md-6"
style={{ 'height': '556px', 'width': '674px', paddingLeft: '0px', paddingRight: '0px' }}
>
<GettingStartedGoogleMap
containerElement={<div style={{ height: '100%' }} />}
mapElement={<div style={{ height: '100%' }} />}
onMapClick={this.handleMarkerClose2.bind(this)}
onMarkerClick={this.handleMarkerClick.bind(this)}
markers={this.state.markers}
center={this.state.center}
onMarkerClose={this.handleMarkerClose.bind(this)}
/>
</div>
<style>{'\
.gm-style-iw + div {\
display: none;\
left: 26px;}\
'}</style>
</div>)}
}
GoogleMaps.propTypes = {
markers: React.PropTypes.array
}
export default GoogleMaps
try this: (props.showInfoIndex == index ) instead of ( props.isOpen )
{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>
)}
use showInfo fnc to setState :
showInfo(a){
setState({showInfoIndex: a })
}
hey your info window is child component, if u want to open infowindow just make info window equivalent to the marker class and make any child component as you want
try this:
<Map
google={this.props.google}
style={style}
initialCenter={{
lat: lat,
lng: lng
}}
zoom={zoom}
onClick={this.onMapClicked}
>
{marker && marker.map((marker, index) => (
<Marker
key={index}
onClick={this.onMarkerClick}
title={marker.place_id}
name={marker.place_name}
position={{ lat: marker.place_latitude, lng: marker.place_longitude }} >
{
<div></div>
}
</Marker>
))}
<InfoWindow
marker={this.state.activeMarker}
visible={this.state.showingInfoWindow}>
<div>
<h3>{this.state.selectedPlace.name}</h3>
</div>
</InfoWindow>
</Map>