As the title says, i'm getting an unwanted page refresh whenever i move the draggable marker. I'd like to set map to pan to the new marker position every time but will settle for solving the page refresh problem at the moment.
I've added snippets of the pieces of code i think are responsible
Any help greatly appreciated
import React, { Component } from 'react';
import { withGoogleMap, GoogleMap, withScriptjs, InfoWindow, Marker } from "react-google-maps";
import { Mutation } from 'react-apollo';
import gql from 'graphql-tag';
import Geocode from "react-geocode";
import User from './User';
import Autocomplete from 'react-google-autocomplete';
import FormBlock from './styles/FormBlock'
import SickButton from './styles/SickButton';
import styled from 'styled-components';
import Form from './styles/Form';
import Error from './ErrorMessage';
import Router from 'next/router';
Geocode.setApiKey( "AIzaSyC7oaBUKbAULgrhMSPx-pT8zr2PG3lpOT4" );
Geocode.enableDebug();
const Mapbox = styled.div`
margin: 0;
padding: 10px;
z-index: 3;
`;
const CREATE_JOB_MUTATION = gql`
mutation CREATE_JOB_MUTATION(
$address: String!
$lat: Float
$lng: Float
$description: String!
$image: String!
$cube: Int!
$reqPickup: String
$instructions: String!
$feedback: String
$pickup: DateTime
$charges: Int
$price: Int
) {
createJob(
address: $address
lat: $lat
lng: $lng
description: $description
image: $image
cube: $cube
reqPickup: $reqPickup
instructions: $instructions
feedback: $feedback
pickup: $pickup
charges: $charges
price: $price
) {
id
address
lat
lng
}
}
`;
class Map extends Component{
constructor( props ){
super( props );
this.state = {
address: '',
lat: '',
lng: '',
city: '',
area: '',
state: '',
image: '',
cube: '',
reqPickup: '',
instructions: '',
feedback: '',
pickup: '',
charges: '0',
price: '0',
mapPosition: {
lat: this.props.center.lat,
lng: this.props.center.lng
},
markerPosition: {
lat: this.props.center.lat,
lng: this.props.center.lng
}
};
this.onPlaceSelected = this.onPlaceSelected.bind(this);
}
handleChange = (e) => {
const { name, type, value } = e.target;
const val = type === 'number' ? parseFloat(value) : value;
this.setState({ [name]: val});
};
uploadFile = async e => {
const files = e.target.files;
const data = new FormData();
data.append('file', files[0]);
data.append('upload_preset', 'sickfits');
const res = await fetch('https://api.cloudinary.com/v1_1/wesbostutorial/image/upload', {
method: 'POST',
body: data,
});
const file = await res.json();
this.setState({
image: file.secure_url,
largeImage: file.eager[0].secure_url,
});
};
/**
* Get the current address from the default map position and set those values in the state
*/
componentDidMount() {
Geocode.fromLatLng( this.state.mapPosition.lat , this.state.mapPosition.lng ).then(
response => {
const address = response.results[0].formatted_address,
addressArray = response.results[0].address_components,
city = this.getCity( addressArray ),
area = this.getArea( addressArray ),
state = this.getState( addressArray );
// console.log( 'city', city, area, state );
this.setState( {
address: ( address ) ? address : '',
area: ( area ) ? area : '',
city: ( city ) ? city : '',
state: ( state ) ? state : '',
lat: this.state.markerPosition.lat,
lng: this.state.markerPosition.lng,
} )
},
error => {
console.error( error );
}
);
};
getCity = ( addressArray ) => {
let city = '';
for( let i = 0; i < addressArray.length; i++ ) {
if ( addressArray[ i ].types[0] && 'administrative_area_level_2' === addressArray[ i ].types[0] ) {
city = addressArray[ i ].long_name;
return city;
}
}
};
/**
* Get the area and set the area input value to the one selected
*
* @param addressArray
* @return {string}
*/
getArea = ( addressArray ) => {
let area = '';
for( let i = 0; i < addressArray.length; i++ ) {
if ( addressArray[ i ].types[0] ) {
for ( let j = 0; j < addressArray[ i ].types.length; j++ ) {
if ( 'sublocality_level_1' === addressArray[ i ].types[j] || 'locality' === addressArray[ i ].types[j] ) {
area = addressArray[ i ].long_name;
return area;
}
}
}
}
};
/**
* Get the address and set the address input value to the one selected
*
* @param addressArray
* @return {string}
*/
getState = ( addressArray ) => {
let state = '';
for( let i = 0; i < addressArray.length; i++ ) {
for( let i = 0; i < addressArray.length; i++ ) {
if ( addressArray[ i ].types[0] && 'administrative_area_level_1' === addressArray[ i ].types[0] ) {
state = addressArray[ i ].long_name;
return state;
}
}
}
};
/**
* And function for city,state and address input
* @param event
*/
/**
* This Event triggers when the marker window is closed
*
* @param event
*/
onInfoWindowClose = ( event ) => {
};
/**
* When the marker is dragged you get the lat and long using the functions available from event object.
* Use geocode to get the address, city, area and state from the lat and lng positions.
* And then set those values in the state.
*
* @param event
*/
onMarkerDragEnd = ( event ) => {
let newLat = event.latLng.lat(),
newLng = event.latLng.lng();
Geocode.fromLatLng( newLat , newLng ).then(
response => {
const address = response.results[0].formatted_address,
addressArray = response.results[0].address_components,
city = this.getCity( addressArray ),
area = this.getArea( addressArray ),
state = this.getState( addressArray );
this.setState( {
address: ( address ) ? address : '',
area: ( area ) ? area : '',
city: ( city ) ? city : '',
state: ( state ) ? state : '',
lat: this.state.markerPosition.lat,
lng: this.state.markerPosition.lng,
markerPosition: {
lat: newLat,
lng: newLng
},
mapPosition: {
lat: newLat,
lng: newLng
},
} )
},
error => {
console.error(error);
}
);
};
/**
* When the user types an address in the search box
* @param place
*/
onPlaceSelected = ( place ) => {
// console.log( 'plc', place );
const address = place.formatted_address,
addressArray = place.address_components,
city = this.getCity( addressArray ),
area = this.getArea( addressArray ),
state = this.getState( addressArray ),
latValue = place.geometry.location.lat(),
lngValue = place.geometry.location.lng();
// Set these values in the state.
this.setState({
address: ( address ) ? address : '',
area: ( area ) ? area : '',
city: ( city ) ? city : '',
state: ( state ) ? state : '',
lat: this.state.markerPosition.lat,
lng: this.state.markerPosition.lng,
markerPosition: {
lat: latValue,
lng: lngValue
},
mapPosition: {
lat: latValue,
lng: lngValue
},
})
};
render(){
const defaultMapOptions = {
disableDefaultUI: true,
};
const AsyncMap = withScriptjs(
withGoogleMap(
props => (
<GoogleMap
google={ this.props.google }
defaultZoom={ this.props.zoom }
defaultCenter={{ lat: this.state.mapPosition.lat, lng: this.state.mapPosition.lng }}
defaultOptions={defaultMapOptions}
>
<Marker google={this.props.google}
name={''}
draggable={true}
onDragEnd={ this.onMarkerDragEnd }
position={{ lat: this.state.markerPosition.lat, lng: this.state.markerPosition.lng }}
/>
<Marker />
</GoogleMap>
)
)
);
let map;
if( this.props.center.lat !== undefined ) {
map = <Mapbox>
<AsyncMap
googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyC7oaBUKbAULgrhMSPx-pT8zr2PG3lpOT4&libraries=places"
loadingElement={
<div style={{ height: `100%` }} />
}
containerElement={
<div style={{ height: this.props.height, margin: '0px', padding: 'auto',}} />
}
mapElement={
<div style={{ height: `100%`, margin: '0px' }} />
}
/>
<Mutation mutation={CREATE_JOB_MUTATION} variables={this.state}>
{(createJob, { loading, error }) => (
<Form
data-test="form"
onSubmit={async e => {
// Stop the form from submitting
e.preventDefault();
// call the mutation
this.setState({ address: this.state.address, lat: this.state.markerPosition.lat, lng: this.state.markerPosition.lng });
console.log(this.state);
const res = await createJob();
// change them to the single job page
Router.push({
pathname: '/orderprocess',
query: { id: res.data.createJob.id },
});
}}>
<Error error={error} />
<fieldset disabled={loading} aria-busy={loading}>
<label htmlFor="address">
<input
type="text"
id="address"
name="address"
placeholder="address"
required
readOnly value={this.state.address}
onChange={this.handleChange}
/>
</label>
<label htmlFor="lat">
<input
type="number"
id="lat"
name="lat"
placeholder="lat"
required
readOnly value={ this.state.markerPosition.lat}
onChange={this.handleChange}
/>
</label>
<label htmlFor="lng">
<input
type="number"
id="lng"
name="lng"
placeholder="lng"
required
readOnly value={this.state.markerPosition.lng}
onChange={this.handleChange}
/>
</label>
{/* <label htmlFor="description">
Describe your waste: Just a few words to describe the materials.
<input
type="text"
id="description"
name="description"
placeholder="eg: wood, bricks, old kitchen tops and a fridge"
required
value={this.state.description}
onChange={this.handleChange}
/>
</label>
<label htmlFor="image" className="pic">
Image: make sure you get it all in shot from a couple of different angles.
<input
type="file"
id="image"
name="image"
placeholder="Upload an image"
required
onChange={this.uploadFile}
/>
{this.state.image && (
<img width="200" src={this.state.image} alt="Upload Preview" />
)}
</label>
<label htmlFor="cube">
Cube: Have a a guess at cm3 of your waste. Don't worry if you get it wrong, its just to help us quote you accuratly.
<input
type="number"
id="cube"
name="cube"
placeholder="Estimate how many cubic metres your waste occupies"
required
value={this.state.cube}
onChange={this.handleChange}
/>
</label>
<label htmlFor="reqPickup">
Required Pickup: Tell us an ideal time to collect/deliver.
<input
type="text"
id="reqPickup"
name="reqPickup"
placeholder="eg: asap "
required
value={this.state.reqPickup}
onChange={this.handleChange}
/>
</label>
<label htmlFor="instructions">
Instructions: Any specific instructions such as desired collection time or access info.
<input
type="text"
id="instructions"
name="instructions"
placeholder="Instructions for the collection team"
required
value={this.state.instructions}
onChange={this.handleChange}
/>
</label> */}
<p
style={{
textAlign: 'center',
}}
>Submit your order and we'll come back to you in just a few moments with a quote and collection time options</p>
<div
style={{
display: 'flex',
margin: 'auto',
justifyContent: 'center',
}}
>
<button
type="submit">SUBMIT</button>
</div>
</fieldset>
</Form>
)}
</Mutation>
</Mapbox>
} else {
map = <div style={{height: this.props.height}} />
}
return( map )
}
}
export default Map
export { CREATE_JOB_MUTATION };