Display only one InfoWindow - reactjs

I realise this has been asked before, however, I'm unable to figure out what I'm doing wrong here. I have a map that displays multiple markers and when I click on a marker it is supposed to displays the InfoWindow about that marker. The problem that when I click on a marker, all the InfoWindow boxes pop up instead of just the one I've clicked on.
const MapWithAMarkerClusterer = compose(
withProps({
googleMapURL: "MY KEY",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withHandlers({
onMarkerClustererClick: () => (markerClusterer) => {
const clickedMarkers = markerClusterer.getMarkers()
}
}),
withStateHandlers(() => ({
isOpen: false,
markerId: ''
}), {
onToggleOpen: ({ isOpen }) => (markerId) => ({
isOpen: !isOpen,
markerId: markerId
})
}),
withScriptjs,
withGoogleMap
)(props =>
<GoogleMap
defaultZoom={4}
defaultCenter={{ lat: -23.696248, lng: 133.880731 }}
>
<MarkerClusterer
onClick={props.onMarkerClustererClick}
averageCenter
enableRetinaIcons
gridSize={60}
>
{props.companies.map(company => (
<span key={company.company_name}>
<Marker
position={company.google_maps.geometry_location}
onClick={() => props.onToggleOpen(company.company_name)}
>
{props.isOpen[props.markerId] && <InfoWindow onCloseClick={props.onToggleOpen}>
<p>Test</p>
</InfoWindow>}
</Marker>
</span>
))}
</MarkerClusterer>
</GoogleMap>
);

Ok, this was a silly mistake. I've updated my code below and it works.
{props.isOpen && (props.markerId == company.company_name) && <InfoWindow onCloseClick={props.onToggleOpen}>
<p>Test</p>
</InfoWindow>}

Related

react-google-maps calls empty InfoWindow

I have problem with first call InfoWindow, it calling like 2 times and one have not any text/info and the second infoWindow have correct my info (number 2 on-screen). If I will click to another my Markeк this empty InfoWindow will stay in the first place. But if I will try to close the empty window and open any my marker this empty window will shows again in a new place.
my code:
function MapCreator() {
const [selectedPoint, setselectedPoint] = useState(null);
const [data,setData] = useState([]);
useEffect(() => {
axios.get('api/coordinates')
.then(values=>{
console.log(values.data);
setData(values.data);
})
const listener = e => {
if (e.key === "Escape") {
setselectedPoint(null);
}
};
window.addEventListener("keydown", listener);
return () => {
window.removeEventListener("keydown", listener);
};
}, []);
return (
<GoogleMap
defaultZoom={14}
defaultCenter={{ lat: 50.444571, lng: 30.559099 }}
>
{data.map(park => (
<Marker
key={park._id}
position={{
lat: park.coordinates.latitude,
lng: park.coordinates.longitude
}}
onClick={() => {
setselectedPoint(park);
}}
icon={{
url: nfcIcon,
scaledSize: new window.google.maps.Size(60, 60)
}}
/>
))}
{selectedPoint && (
<InfoWindow
onCloseClick={() => {
setselectedPoint(null);
}}
position={{
lat: selectedPoint.coordinates.latitude,
lng: selectedPoint.coordinates.longitude
}}
>
<div>
<h2>Device ID: {selectedPoint.identificatorNFC}</h2>
<p>Date: {new Date(selectedPoint.date) .toUTCString()}</p>
</div>
</InfoWindow>
)}
</GoogleMap>
);
}
const MapWrapped = withScriptjs(withGoogleMap(MapCreator));
export default function App() {
return (
<div style={{ width: `100%`, height: "100vh" }}>
<MapWrapped
googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${
keys.googleApi
}`}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100%` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
Tbh, I don't see any kind of problem in your code but I suggest try this out:
function MapCreator() {
const [selectedPoint, setselectedPoint] = useState(null);
const [data,setData] = useState([]);
useEffect(() => {
axios.get('api/coordinates')
.then(values=>{
console.log(values.data);
setData(values.data);
})
const listener = e => {
if (e.key === "Escape") {
setselectedPoint(null);
}
};
window.addEventListener("keydown", listener);
return () => {
window.removeEventListener("keydown", listener);
};
}, []);
return (
<GoogleMap
defaultZoom={14}
defaultCenter={{ lat: 50.444571, lng: 30.559099 }}
>
{data.map(park => (
<Marker
key={park._id}
position={{
lat: park.coordinates.latitude,
lng: park.coordinates.longitude
}}
onClick={() => {
setselectedPoint(park);
}}
icon={{
url: nfcIcon,
scaledSize: new window.google.maps.Size(60, 60)
}}
>
{selectedPoint && selectedPoint._id === park._id && (
<InfoWindow onCloseClick={() => setselectedPoint(null)}
>
<div>
<h2>Device ID: {selectedPoint.identificatorNFC}</h2>
<p>Date: {new Date(selectedPoint.date) .toUTCString()}</p>
</div>
</InfoWindow>
)}
</Marker>
))}
</GoogleMap>
);
}
const MapWrapped = withScriptjs(withGoogleMap(MapCreator));
export default function App() {
return (
<div style={{ width: `100%`, height: "100vh" }}>
<MapWrapped
googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${
keys.googleApi
}`}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100%` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}

Access variable outside render

I'm having a problem in my code. I already can make a marker on the map with lat and lng. But I want to display a simple span with the coordinates under the map. I try to access this.props.markerPosition and it's null in render.
What is the issue here?
https://stackblitz.com/edit/react-snxake
const WrappedMap = compose(
withStateHandlers(() => ({
isMarkerShown: false,
markerPosition: null
}), {
onMapClick: ({ isMarkerShown }) => (e) => ({
markerPosition: e.latLng,
isMarkerShown:true
})
}),
withScriptjs,
withGoogleMap
)
(props =>
<GoogleMap
defaultZoom={8}
defaultCenter={{ lat: -34.397, lng: 150.644 }}
onClick={props.onMapClick}
>
{props.isMarkerShown && <Marker position={props.markerPosition} onClick={props.onMarkerClick} defaultOptions={{ styles: mapStyles}} />}
</GoogleMap>
)
export default class ParkingSpotsSettings extends React.Component {
state = {
evaluationExecuted: false,
evaluation: false
};
constructor() {
super();
this.state = {
coordinates: [],
title: '',
description: '',
capacity: 0
}
}
componentDidMount() { }
render() {
return (
<div className="App">
<Navigation />
<div className="container-fluid">
<div className="row">
<div className="col-md-6" style={{ width: "100vw", height: "40vh" }}>
<WrappedMap googleMapURL={`https://maps.googleapis.com/maps/api/js?key=v=3.exp&libraries=geometry,drawing,places`}
loadingElement={<div style={{ height: "100%" }} />}
containerElement={<div style={{ height: "100%" }} />}
mapElement={<div style={{ height: "100%" }} />}
/>
</div>
<span>Coordinates are: {this.props.markerPosition}</span>
</div>
</div>
</div >
);
}
}
Your prop is called position not markerPosition. So you need to use this.props.position.

react-google-maps: multiple info windows opening up

This is probably going to be a stupidly simple react question but please bear with me.
I am trying to run a react-google-maps with multiple markers with info windows. Here is the code:
const MapWithADirectionsRenderer = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?key=AIzaSyDf-yIqxErTkbWzKhLox7nAANnrfDIY190&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `800px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withStateHandlers(() => ({
isOpen: false,
}), {
onToggleOpen: ({ isOpen }) => () => ({
isOpen: !isOpen,
})
}),
withScriptjs,
withGoogleMap,
})
)(props =>
<GoogleMap
defaultZoom={13}
defaultCenter={new google.maps.LatLng(42.357064, -71.062577)}
>
<Marker
position={{ lat: 42.3381437, lng: -71.0475773 }}
onClick={props.onToggleOpen}
>
{props.isOpen && <InfoWindow onCloseClick={props.onToggleOpen}>
<h3>South Boston</h3>
</InfoWindow>}
</Marker>
<Marker
position={{ lat: 42.3875968, lng: -71.0994968 }}
onClick={props.onToggleOpen}
>
{props.isOpen && <InfoWindow onCloseClick={props.onToggleOpen}>
<h3>Somervil</h3>
</InfoWindow>}
</Marker>
{props.directions && <DirectionsRenderer directions={props.directions} />}
</GoogleMap>
);
When I click one of the markers, the info windows for all the markers toggle open. How do I just toggle open the info window of the marker I click?
I would suggest to introduce a component:
class MarkerWithInfoWindow extends React.Component {
constructor() {
super();
this.state = {
isOpen: false
}
this.onToggleOpen = this.onToggleOpen.bind(this);
}
onToggleOpen() {
this.setState({
isOpen: !this.state.isOpen
});
}
render() {
return (<Marker
position={this.props.position}
onClick={this.onToggleOpen}>
{this.state.isOpen && <InfoWindow onCloseClick={this.onToggleOpen}>
<h3>{this.props.content}</h3>
</InfoWindow>}
</Marker>)
}
}
to control info window per marker via MarkerWithInfoWindow state:
<GoogleMap
defaultZoom={13}
defaultCenter={new google.maps.LatLng(42.357064, -71.062577)}>
<MarkerWithInfoWindow position={{ lat: 42.3381437, lng: -71.0475773 }} content="South Boston" />
<MarkerWithInfoWindow position={{ lat: 42.3875968, lng: -71.0994968 }} content="Somervil" />
</GoogleMap>
Demo

geolocation in React, use react-google-maps

How to change defaultCenter in react-google-maps ?
I need to find my geolocation and change default values lat and lng.
import React from "react";
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps";
const getLocation = () =>{
const pos = {};
const geolocation = navigator.geolocation;
if (geolocation) {
geolocation.getCurrentPosition(findLocal, showEror);
}
function findLocal(position){
pos.lat = position.coords.latitude;
pos.lng = position.coords.longitude;
}
function showEror(){console.log(Error)}
return pos;
};
const myLocation = getLocation(); // object has lat and lng
I need to transfer my data to the component MapWithAMarker next: Ğ¡enter={myLocation} and Marker position={myLocation}
class GoogleMapCenter extends React.Component{
render(){
const MapWithAMarker = withScriptjs(withGoogleMap(props =>
<GoogleMap
defaultZoom={10}
defaultCenter={{ lat: -34.397, lng: 150.644 }}>
{props.isMarkerShown && <Marker position={{ lat: -34.397, lng: 150.644 }} />}
</GoogleMap>
));
return(
<MapWithAMarker
isMarkerShown
googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyC4R6AN7SmujjPUIGKdyao2Kqitzr1kiRg&v=3.exp"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
)
}
}
export default GoogleMapCenter;
If I use this.props, it does not work.
<MapWithAMarker
center={this.props.myLocation}
position={this.props.myLocation}
isMarkerShown
googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyC4R6AN7SmujjPUIGKdyao2Kqitzr1kiRg&v=3.exp"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
or
<GoogleMap
defaultZoom={10}
defaultCenter={this.props.myLocation}>
{props.isMarkerShown && <Marker position={this.props.myLocation} />}
</GoogleMap>
Default properties like defaultCenter could only be set as initial state, center property could be used instead to re-render (center) the map.
The following example demonstrates how to center the map based on current location
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
currentLatLng: {
lat: 0,
lng: 0
},
isMarkerShown: false
}
}
showCurrentLocation = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
position => {
this.setState(prevState => ({
currentLatLng: {
...prevState.currentLatLng,
lat: position.coords.latitude,
lng: position.coords.longitude
},
isMarkerShown: true
}))
}
)
} else {
error => console.log(error)
}
}
componentDidMount() {
this.showCurrentLocation()
}
render() {
return (
<div>
<MapWithAMarker
isMarkerShown={this.state.isMarkerShown}
currentLocation={this.state.currentLatLng} />
</div>
);
}
}
where
const MapWithAMarker = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withScriptjs,
withGoogleMap
)((props) =>
<GoogleMap
defaultZoom={8}
center={{ lat: props.currentLocation.lat, lng: props.currentLocation.lng }}
>
{props.isMarkerShown && <Marker position={{ lat: props.currentLocation.lat, lng: props.currentLocation.lng }} onClick={props.onMarkerClick} />}
</GoogleMap>
)
Demo (edit)

Unable to render the Google map on state change

I am trying to change the state of salesPropertyInfoWindowIn by assigning an
array salesPropertyInfoWindowOut that is defined globally.
initial value of
salesPropertyInfoWindowIn :
[false,false,false,false,false,false,false,false,false,false]
onMarkerClick method changes the value of index passed as an parameter then assigns the value in salesPropertyInfoWindowIn. However, this doesn't rerender the map. Please help me by suggesting some solution.
const MapWithAMarkerClusterer = compose(
withProps({
googleMapURL:
"https://maps.googleapis.com/maps/api/js?key=AIzaSyDlMypBHZKOOgwp7PBHrQSvf75Y1sM2gnU&v=3.exp&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `390px` }} />,
mapElement: <div style={{ height: `100%` }} />
}),
withStateHandlers(
() => ({
salesPropertyInfoWindowIn: salesPropertyInfoWindowOut,
isOpen: false,
}),
{
onToggleOpen: ({isOpen}) => () => ({
isOpen: !isOpen
}),
onMarkerClick: ({salesPropertyInfoWindowIn}) => (marker, i) => (
salesPropertyInfoWindowOut[i] = !salesPropertyInfoWindowOut[i],
{salesPropertyInfoWindowIn: salesPropertyInfoWindowOut}
)
}),
withScriptjs,
withGoogleMap)(props => (
<GoogleMap
defaultZoom={15}
defaultCenter={
home.currentProperty != null
? {
lat: parseFloat(home.currentProperty.property.location.lat),
lng: parseFloat(home.currentProperty.property.location.lon)
}
: ""
}
>
<MarkerClusterer averageCenter enableRetinaIcons gridSize={10}>
{home.propSalesData != undefined || home.propSalesData != null
? props.markers.map((marker, i) => (
<Marker
icon={salesPropertyMarkerImage}
onClick={() => props.onMarkerClick(marker, i)}
key={i}
position={{
lat: parseFloat(marker.location.lat),
lng: parseFloat(marker.location.lon)
}}
>
{(props.salesPropertyInfoWindowIn[i] == true) ?
(console.log('Inside', props.salesPropertyInfoWindowIn[i]),
<InfoWindow>
<text>
{home.propSalesData[i].agent.name != undefined ||
home.propSalesData[i].agent.name != null
? "Agent: " + home.propSalesData[i].agent.name
: "Purchaser: " +
home.propSalesData[i].saleParticipants
.purchasersSummary}
</text>
</InfoWindow>
) : ""}
</Marker>
))
: ""}
You can try storing the index of the clicked marker, instead of using the 2 arrays salesPropertyInfoWindowIn / salesPropertyInfoWindowOut.
onMarkerClick(index) {
this.setState({clickedMarkerIndex: index})
}
Then, to render InfoWindows only on clicked markers:
{props.markers.map((marker, index) => {
<Marker onClick={() => props.onMarkerClick(index)}>
{props.clickedMarkerIndex === index &&
<InfoWindow> etc etc
}
</Marker>
})

Resources