Reputation: 113
I have an app that uses Google map api inside reactJS:
https://github.com/strangebnb/react-airbnb
I've been successfully able to do everything I need to do except using a ReactJS component as the content string for a Google Map API infowindow
I am not using any libraries or npm packages to merge the 2. Just straight Google Maps API and ReactJS.
Here is my code for the entire component that will render the map:
import React from 'react'
import ReactDOM from 'react-dom'
import axios from 'axios'
import Navbar from '../navbar/Navbar.js'
import moment from 'moment'
import Rheostat from 'rheostat'
import _ from 'lodash'
import Slider from 'react-slick'
import PrevArrow from './PrevArrow'
import DateRangePickerGmapPage from '../date-range-picker/DateRangePickerGmapPage.jsx';
require('./searchResults.scss');
require('./_datepicker2.scss');
var sliderMin = 0;
export default class SearchResults extends React.Component {
constructor(props) {
super(props)
this.state = {
zoom: 12,
iCenter: {
lng: -90.1056957,
lat: 29.9717272
},
checker: false,
icon: {
path: 'M 0,0 20,0 20,16 14,16 10,24 6,16 0,16 z',
fillColor: '#FF5A5F',
fillOpacity: 1,
scale: 1.5,
strokeColor: 'RGBA(100,100,100,0.5)',
strokeWeight: 1,
},
entireHome: false,
privateRoom: false,
sharedRoom: false,
location: null,
data: null,
startDate: null,
endDate: null,
numGuests: 1,
values: [0,100],
sliderMin: 0,
sliderMax: 100,
roomTypeSelected: null,
picture_urls: [],
propertyNames: [],
star_rating: [],
price_array: []
}
axios.get('/getData').then(response => {
const x = response.data;
this.setState({
iCenter: {
lat: x.center_lat,
lng: x.center_lng
},
location: x.canonical_location_en
})
this.setState({
data: x,
location: x.location,
startDate: x.startDate,
endDate: x.endDate,
numGuests: x.numGuests,
sliderMax: x.max_price_total,
sliderMin: x.min_price_total,
values: [x.min_price_total, x.max_price_total]
}, ()=>{
this.renderMap(x);
});
})
}
static propTypes() {
initialCenter: React.PropTypes.objectOf(React.PropTypes.number).isRequired
}
render = () => {
var settings = {
// prevArrow: {PrevArrow},
arrows: true,
infinite: true,
slidesToShow: 1,
slidesToScroll: 1,
speed: 0.0001
};
let arrOfSliders = [];
if(this.state.picture_urls.length != 0){
for(let i = 0; i < this.state.picture_urls.length; i++){
var slider = <div><Slider className='slider' {...settings}>
<div className='img-container'><img className='slider-img' src={this.state.picture_urls[i][0]} ></img></div>
<div className='img-container'><img className='slider-img' src={this.state.picture_urls[i][1]} ></img></div>
<div className='img-container'><img className='slider-img' src={this.state.picture_urls[i][2]} ></img></div>
<div className='img-container'><img className='slider-img' src={this.state.picture_urls[i][3]} ></img></div>
<div className='img-container'><img className='slider-img' src={this.state.picture_urls[i][4]} ></img></div>
</Slider>
<p className='img-title'>{this.state.propertyNames[i]}</p>
<p>{this.state.star_rating[i]}</p>
</div>
arrOfSliders.push(slider);
}
}
return(
<div>
<Navbar/>
<div className = 'UpdatedText'>
<p>Current Zoom: {this.state.zoom} </p>
</div>
<main className = 'container-search'>
<div className = 'cards-container'>
<div className = 'date-panel'>
<span>Dates</span>
<DateRangePickerGmapPage location = {this.state.location} renderMap = {this.renderMap.bind(this)} className = 'date-picker'/> </div>
<div className = 'room-panel'>
<span> Room Types </span>
<div className = 'checkboxes'>
<label>Entire Home</label><input className='checkbox' id='entireHome' type='checkbox' name='Entire home/apt' value={this.state.entireHome} onChange={this.handleRoomTypes}/>
<label>Private Room</label><input className='checkbox' id='privateRoom' type='checkbox' name='Private room' value={this.state.privateRoom} onChange={this.handleRoomTypes}/>
<label>Shared Room</label><input className='checkbox' id='sharedRoom' type='checkbox' name='Shared room' value={this.state.sharedRoom} onChange={this.handleRoomTypes}/>
</div>
</div>
<div>
<Rheostat min={this.state.sliderMin} max={this.state.sliderMax} onValuesUpdated={this.updateValue} values={this.state.values} className = 'rheostat' />
<ol className='tempVals'>
<lh>Values</lh>
{this.state.values.map((value, i) => (
<li className='val' key={i}>
{this.props.formatValue ? this.props.formatValue(value) : value}
</li>
))}
</ol>
</div>
<div className='arrayOfSliders'>
{arrOfSliders.map((slider, i)=>{
return(
<div className='slider-container' key={i}>{slider}</div>
)
})}
</div>
</div>
<div className = 'GMap-canvas' ref = "mapCanvas" > </div>
</main>
</div>
)
}
updateValue = (sliderState) => {
this.setState({
values: sliderState.values,
}, this.renderMap(this.state.roomTypeSelected, this.state.values));
}
handleRoomTypes = (e) => {
if (e.target.value === 'false') {
this.setState({[e.target.id]: true}, ()=>{
let arr = [this.state.entireHome, this.state.privateRoom, this.state.sharedRoom];
return this.renderMap(this.convertToNames(arr));
});
} else if (e.target.value === 'true') {
this.setState({[e.target.id]: false}, ()=>{
let arr = [this.state.entireHome, this.state.privateRoom, this.state.sharedRoom];
return this.renderMap(this.convertToNames(arr));
}
);
}
}
convertToNames = (arr) => {
var names = ['Entire home/apt', 'Private room', 'Shared room'];
for(let i = 0; i < arr.length; i++){
if(arr[i] === false){
names.splice(i,1);
arr.splice(i,1);
i--;
}
}
console.log('names: ', names);
this.setState({roomTypeSelected: names});
return names
}
componentDidUnMount() {
google.maps.event.clearListeners(map, 'zoom_changed')
}
createMap = () => {
let mapOptions = {
zoom: this.state.zoom,
center: this.mapCenter()
}
return new google.maps.Map(this.refs.mapCanvas, mapOptions)
}
mapCenter = () => {
return new google.maps.LatLng(
this.state.iCenter.lat,
this.state.iCenter.lng
)
}
createMarker = (lat, lng, price) => {
var marker = new google.maps.LatLng(
lat, lng
);
return new Marker({
position: marker,
map: this.map,
icon: {
path: SQUARE_PIN,
fillOpacity: 0,
strokeColor: '#9BA198',
strokeWeight: 0,
},
map_icon_label: '<span class=price>$' + price + '</span>'
})
}
createInfoWindow = () => {
let contentString = `<div>hi</div>`
return new google.maps.InfoWindow({
map: this.map,
anchor: this.marker,
content: contentString
})
}
handleZoomChange = () => {
this.setState({
zoom: this.map.getZoom()
})
}
renderMap = (arr, priceRange = [null,null]) => {
console.log(arr);
axios.post('/search',{
searchVal: this.state.location,
startDate: this.state.startDate,
endDate: this.state.endDate,
numGuests: this.state.numGuests,
room_types: arr,
price_min: this.state.sliderMin,
price_max: this.state.sliderMax,
}).then(response => {
const x = response.data;
let listingsArray = response.data.results_json.search_results;
this.map = this.createMap()
this.latlngbounds = new google.maps.LatLngBounds();
let pics_array = [];
let propertyNames = [];
let star_rating = [];
let price_array = [];
for (let i = 0; i < listingsArray.length; i++) {
const lat = listingsArray[i].listing.lat
const lng = listingsArray[i].listing.lng
this.marker = this.createMarker(lat, lng, listingsArray[i].pricing_quote.rate.amount)
this.infoWindow = this.createInfoWindow()
var myLatLng = new google.maps.LatLng(lat, lng);
this.latlngbounds.extend(myLatLng);
pics_array.push(listingsArray[i].listing.picture_urls);
propertyNames.push(listingsArray[i].listing.name);
star_rating.push(listingsArray[i].listing.star_rating);
price_array.push(listingsArray[i].pricing_quote.rate.amount);
this.setState({picture_urls: pics_array,
propertyNames: propertyNames,
star_rating: star_rating,
price_array: price_array},
()=> { console.log('Testing ES6: ', this.state.propertyNames) }
)
}
console.log('max total price:', x.max_price_total)
if(x.max_price_total === null && x.min_price_total === null){
const min = Math.min(...price_array);
const max = Math.max(...price_array);
this.setState({
sliderMin: min,
sliderMax: max,
values: [min, max]
})
}
this.map.fitBounds(this.latlngbounds);
this.setState({
iCenter: {
lat: x.center_lat,
lng: x.center_lng
}
})
google.maps.event.addListener(this.map, 'zoom_changed', () => this.handleZoomChange())
})
}
}
In the method below, my contentString needs to be a react component instead html or a string, which is what Google API wants.
createInfoWindow = () => {
let contentString = `<div>hi</div>`
return new google.maps.InfoWindow({
map: this.map,
anchor: this.marker,
content: contentString
})
}
Infowindows are rendered in the renderMap method, along with the map and markers. Is there a work around this or am I sore out of luck?
Upvotes: 2
Views: 1561
Reputation: 3165
You can try
ReactDOMServer.renderToString
https://facebook.github.io/react/docs/top-level-api.html
an example code could be
import ReactDOMServer from 'react-dom/server';
createInfoWindow = () => {
let contentString = ReactDOMServer.renderToString(<YourComponent/>);
return new google.maps.InfoWindow({
map: this.map,
anchor: this.marker,
content: contentString
})
}
Upvotes: 3