I'm having a problem while viewing google maps in my react native app. I ran a test with an HTML file and it displays. But in my app open blank but shows the logo of google. Below my map code.
App.js
import React, { Component, Fragment } from 'react';
import { View, Image } from 'react-native';
import MapView, { Marker } from 'react-native-maps';
import Geocoder from 'react-native-geocoding';
import { getPixelSize } from '../../components/utils';
import Search from '../Search';
import Directions from '../Directions';
import Details from '../Details';
import markerImage from '../../assets/marker.png';
import backImage from '../../assets/back.png';
import {
Back,
LocationBox,
LocationText,
LocationTimeBox,
LocationTimeText,
LocationTimeTextSmall
} from './styles';
Geocoder.init('MY API');
export default class Map extends Component {
state = {
region: null,
destination: null,
duration: null,
location: null
};
async componentDidMount () {
navigator.geolocation.getCurrentPosition(
async ({ coords: { latitude, longitude } }) => {
const response = await Geocoder.from({ latitude, longitude });
const address = response.results[0].formatted_address;
const location = address.substring(0, address.indexOf(','));
console.log(latitude);
console.log(longitude);
this.setState({
location,
region: {
latitude,
longitude,
latitudeDelta: 0.0143,
longitudeDelta: 0.0134
}
});
}, // sucesso
() => {}, // erro
{
timeout: 2000,
enableHighAccuracy: true,
maximumAge: 1000
}
);
}
handleLocationSelected = (data, { geometry }) => {
const {
location: { lat: latitude, lng: longitude }
} = geometry;
this.setState({
destination: {
latitude,
longitude,
title: data.structured_formatting.main_text
}
});
};
handleBack = () => {
this.setState({ destination: null });
};
render () {
const { region, destination, duration, location } = this.state;
return (
<View style={{ flex: 1 }}>
<MapView
style={{ flex: 1 }}
region={region}
showsUserLocation
loadingEnabled
ref={el => (this.mapView = el)}
>
{destination && (
<Fragment>
<Directions
origin={region}
destination={destination}
onReady={result => {
this.setState({ duration: Math.floor(result.duration) });
this.mapView.fitToCoordinates(result.coordinates, {
edgePadding: {
right: getPixelSize(50),
left: getPixelSize(50),
top: getPixelSize(50),
bottom: getPixelSize(350)
}
});
}}
/>
<Marker
coordinate={destination}
anchor={{ x: 0, y: 0 }}
image={markerImage}
>
<LocationBox>
<LocationText>{destination.title}</LocationText>
</LocationBox>
</Marker>
<Marker coordinate={region} anchor={{ x: 0, y: 0 }}>
<LocationBox>
<LocationTimeBox>
<LocationTimeText>{duration}</LocationTimeText>
<LocationTimeTextSmall>MIN</LocationTimeTextSmall>
</LocationTimeBox>
<LocationText>{location}</LocationText>
</LocationBox>
</Marker>
</Fragment>
)}
</MapView>
{destination ? (
<Fragment>
<Back onPress={this.handleBack}>
<Image source={backImage} />
</Back>
<Details />
</Fragment>
) : (
<Search onLocationSelected={this.handleLocationSelected} />
)}
</View>
);
}
}
In androidManifest i put the correct code and the rest also, I do not know what else to do , I think it might be something with my emulator, can anyone give me a guideline?
you need to install google play services or Gapps on emulator.
Related
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>
);
}
I want to make a map where user can select his current location as well and can select location from other than his current location...But i am getting this error ... "Error while updating property 'region' of a view managed by: AIRMap null Longitude"......Here i am attaching my Map Class code too ...Please help me
import React from 'react';
import PropTypes from 'prop-types';
import { View, StyleSheet, Animated, Platform, UIManager, TouchableOpacity, Text, ViewPropTypes } from 'react-native';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import Entypo from 'react-native-vector-icons/Entypo';
import axios from 'axios';
import Events from 'react-native-simple-events';
import MapView from 'react-native-maps';
import AutoCompleteInput from './AutoCompleteInput'
const PLACE_DETAIL_URL = 'https://maps.googleapis.com/maps/api/place/details/json';
const DEFAULT_DELTA = { latitudeDelta: 0.015, longitudeDelta: 0.0121 };
export default class Map extends React.Component {
static propTypes = {
apiKey:"AIzaSyCqDF-mH8qkUQ4z0qB1exxxxxxI0FYRACs",
initialLocation: PropTypes.shape({
latitude: PropTypes.number,
longitude: PropTypes.number,
}).isRequired,
markerColor: PropTypes.string,
actionButtonStyle: ViewPropTypes.style,
actionTextStyle: Text.propTypes.style,
actionText: PropTypes.string,
onLocationSelect: PropTypes.func,
debounceDuration: PropTypes.number,
components: PropTypes.arrayOf(PropTypes.string),
};
static defaultProps = {
markerColor: 'black',
actionText: 'DONE',
onLocationSelect: () => ({}),
debounceDuration: 300,
components: [],
};
constructor(props) {
super(props);
if (Platform.OS === 'android')
{
UIManager.setLayoutAnimationEnabledExperimental &&
UIManager.setLayoutAnimationEnabledExperimental(true);
}
}
componentDidMount() {
Events.listen('InputBlur', this.constructor.displayName, this._onTextBlur);
Events.listen('InputFocus', this.constructor.displayName, this._onTextFocus);
Events.listen('PlaceSelected', this.constructor.displayName, this._onPlaceSelected);
}
componentWillUnmount() {
Events.rm('InputBlur', this.constructor.displayName);
Events.rm('InputFocus', this.constructor.displayName);
Events.rm('PlaceSelected', this.constructor.displayName);
}
state = {
inputScale: new Animated.Value(1),
inFocus: false,
region: {
...DEFAULT_DELTA,
...this.props.initialLocation,
},
};
_animateInput = () => {
Animated.timing(this.state.inputScale, {
toValue: this.state.inFocus ? 1.2 : 1,
duration: 300,
}).start();
};
_onMapRegionChange = region => {
this._setRegion(region, false);
if (this.state.inFocus) {
this._input.blur();
}
};
_onMapRegionChangeComplete = region => {
this._input.fetchAddressForLocation(region);
};
_onTextFocus = () => {
this.state.inFocus = true;
this._animateInput();
};
_onTextBlur = () => {
this.state.inFocus = false;
this._animateInput();
};
_setRegion = (region, animate = true) => {
this.state.region = { ...this.state.region, ...region };
if (animate) this._map.animateToRegion(this.state.region);
};
_onPlaceSelected = placeId => {
this._input.blur();
axios.get(`${PLACE_DETAIL_URL}?key=${this.props.apiKey}&placeid=${placeId}`).then(({ data }) => {
let region = (({ lat, lng }) => ({ latitude: lat, longitude: lng }))(data.result.geometry.location);
this._setRegion(region);
});
};
_getCurrentLocation = () => {
navigator.geolocation.getCurrentPosition(position => {
let location = (({ latitude, longitude }) => ({ latitude, longitude }))(position.coords);
this._setRegion(location);
});
};
render() {
let { inputScale } = this.state;
return (
<View style={styles.container}>
<MapView
ref={mapView => (this._map = mapView)}
style={styles.mapView}
region={this.state.region}
showsMyLocationButton={true}
showsUserLocation={false}
onPress={({ nativeEvent }) => this._setRegion(nativeEvent.coordinate)}
onRegionChange={this._onMapRegionChange}
onRegionChangeComplete={this._onMapRegionChangeComplete}
/>
<Entypo
name={'location-pin'}
size={30}
color={this.props.markerColor}
style={{ backgroundColor: 'transparent' }}
/>
<View style={styles.fullWidthContainer}>
<AutoCompleteInput
ref={input => (this._input = input)}
apiKey={this.props.apiKey}
style={[styles.input, { transform: [{ scale: inputScale }] }]}
debounceDuration={this.props.debounceDuration}
components={this.props.components}
/>
</View>
<TouchableOpacity
style={[styles.currentLocBtn, { backgroundColor: this.props.markerColor }]}
onPress={this._getCurrentLocation}
>
<MaterialIcons name={'my-location'} color={'white'} size={25} />
</TouchableOpacity>
<TouchableOpacity
style={[styles.actionButton, this.props.actionButtonStyle]}
onPress={() => this.props.onLocationSelect({ ...this.state.region, address: this._input.getAddress() })}
>
<View>
<Text style={[styles.actionText, this.props.actionTextStyle]}>{this.props.actionText}</Text>
</View>
</TouchableOpacity>
{this.props.children}
</View>
);
}
}
If you use showsUserLocation props you need to add the ACCESS_FINE_LOCATION permission into your AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
hope it will help!
first set default region so that it wont crash on start.
const LATITUDE = 40.665364;
const LONGITUDE = -74.213377;
const LATITUDE_DELTA = 0.0043;
const LONGITUDE_DELTA = 0.0034;
set region props default value this.state.region which is null, which cause this error try adding its default value in state. like this
state = {
region:{
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA
}
}
<MapView
ref={map => (this.map = map)}
customMapStyle={uber_style}
initialRegion={{
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA
}}
region={this.state.region}
onMapReady={this.onMapLayout}
maxZoomLevel={this.state.maxZoomLevel}
provider={PROVIDER_GOOGLE}
loadingIndicatorColor="#e21d1d"
style={{
flex: 1,
width: Metrics.screenWidth,
height: Metrics.screenHeight
}}
showsBuildings={true}
loadingEnabled={true}
// showsUserLocation={true}
onRegionChangeComplete={this.onRegionChangeComplete}
>
Below is my sample code:
var coords = this.props.navigation.state.params.locationvalue; //getting location from props.
try {
this.map.animateToRegion({
...this.state.locationArea,
latitude: coords.latitude,
longitude: coords.longitude
});
this.setState(prevState => {
return {
locationArea: {
...prevState.locationArea,
latitude: coords.latitude,
longitude: coords.longitude
}
};
});
} catch (error) {
console.log("error map.animateRegion(): " + JSON.stringify(error))
}
Here I was passing the wrong value of latitude and longitude when using this.map.animateToRegion method.
You can check that you are passing the exact value of latitude and longitude while using animateToRegion with MapView. I hope this solution helps.
For me, the issue was a typo error. Region lat and long are in a string. Also, it shouldn’t be blank or undefined .
You can use Number or parseFloat to parse.
const LATITUDE = '70.664'; //type string
const LONGITUDE = '-58.23077';
Fix to this is :
region:{
latitude: parseFloat(LATITUDE), //or Number(LATITUDE)
longitude: parseFloat(LONGITUDE),
latitudeDelta: 0.02,
longitudeDelta: 0.02,
}
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}
/>
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>
I would like to display InfoWindow on Marker click. I followed some tutorials and I used react-google-maps for my project. I would like my app to work like this: "https://tomchentw.github.io/react-google-maps/basics/pop-up-window" but my code is a little bit different.
class Map extends React.Component {
handleMarkerClick(){
console.log("Clicked");
}
handleMarkerClose(){
console.log("CLOSE");
}
render(){
const mapContainer= <div style={{height:'100%',width:'100%'}}></div>
//fetch markers
const markers = this.props.markers.map((marker,i) => {
return (
<Marker key={i} position={marker.location} showTime={false} time={marker.time} onClick={this.handleMarkerClick} >
{
<InfoWindow onCloseClick={this.handleMarkerClose}>
<div>{marker.time}</div>
</InfoWindow>
}
</Marker>
)
})
/* set center equals to last marker's position */
var centerPos;
if(markers[markers.length-1]!== undefined)
{
centerPos=markers[markers.length-1].props.position;
}
else {
centerPos={};
}
return (
<GoogleMapLoader
containerElement={mapContainer}
googleMapElement={
<GoogleMap
defaultZoom={17}
center={centerPos}
>
{markers}
</GoogleMap>
}/>
);
}
}
export default Map;
I got "this.props.markers" from another class component, which fetching data from URL. I am almost sure, that it is easy problem to solve. Currently on marker click in console I got "Clicked" and on Marker close "CLOSE" as you can guess from above code it is because of handleMarkerClick() and handleMarkerClose(). I want to have pop-window with InfoWindow.
What should I do to make it work?
Here is heroku link : App on heroku
Hi I came across the same requirement. I did this (I am using redux and redux-thunk) :
GoogleMap.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import {
withGoogleMap,
GoogleMap,
Marker,
InfoWindow
} from 'react-google-maps';
import { onMarkerClose } from '../actions/Cabs';
const GettingStartedGoogleMap = withGoogleMap(props => (
<GoogleMap
defaultZoom={12}
defaultCenter={{ lat: 12.9716, lng: 77.5946 }}
>
{props.markers.map( (marker, index) => (
<Marker {...marker} onClick={() => props.onMarkerClose(marker.key)}>
{marker.showInfo &&(
<InfoWindow onCloseClick={() => props.onMarkerClose(marker.key)}>
<div>
<h1>Popover Window</h1>
</div>
</InfoWindow>
)}
</Marker>
))}
</GoogleMap>
));
class CabType extends Component{
constructor(props){
super(props);
}
render(){
if(this.props.cabs.length === 0){
return <div>loading...</div>
}
return(
<div className="map-wrapper">
<GettingStartedGoogleMap
containerElement={
<div style={{ height: '100%' }} />
}
mapElement={
<div style={{ height: '100%' }} />
}
onMarkerClose = {this.props.onMarkerClose}
markers={this.props.showMap ? this.props.markers : []}
/>
</div>
)
}
}
export default connect(store => {return {
cabs : store.cabs,
markers: store.markers
}}, {
onMarkerClose
})(CabType);
Action.js
const getMarkers = (cabs , name) => dispatch => {
let markers = [];
let data = {};
cabs.map(cab => {
if(cab.showMap){
data = {
position: {
lat : cab.currentPosition.latitude,
lng : cab.currentPosition.longitude
},
showInfo: false,
key: cab.cabName,
icon: "/images/car-top.png",
driver: cab.driver,
contact: cab.driverContact,
};
markers.push(data);
}
});
dispatch(emitMarker(markers));
};
function emitSetMarker(payload){
return{
type: SET_MARKER,
payload
}
}
export const onMarkerClose = (key) => dispatch => {
dispatch(emitSetMarker(key))
};
RootReducer.js
import { combineReducers } from 'redux';
import { cabs } from "./Cabs";
import { markers } from "./Markers";
const rootReducer = combineReducers({
cabs,
markers,
});
export default rootReducer;
MarkerReducer.js
import { GET_MARKERS, SET_MARKER } from "../types"
export const markers = (state = [], action) => {
switch (action.type){
case GET_MARKERS:
return action.payload;
case SET_MARKER:
let newMarker = state.map(m => {
if(m.key === action.payload){
m.showInfo = !m.showInfo;
}
return m;
});
return newMarker;
default: return state;
}
};
Sorry for a long post but this is code which is tested and running. Cheers!