Search code examples
androidreact-nativegoogle-mapsexpogoogle-places-autocomplete

set marker based on react native google places autocomplete


I want to generate a marker when user search for the location using react-native-google-places-autocomplete. I'm using expo react native. Currently, the marker is set at a fixed location. I want it to be set based on the input given by user through react-native-google-places-autocomplete. How can I achieve this? Below are my codes:

<View>
      <GooglePlacesAutocomplete
                placeholder=""
                query={{
                    key: GOOGLE_PLACES_API_KEY,
                    language: 'en', // language of the results
                }}
                fetchDetails={true}
                onPress={(data, details:any) => { 
                    setDestinationLatitude(details.geometry.location.lat.toString()); 
                    setDestinationLongitude(details.geometry.location.lng.toString()); 
                }}
                onFail={(error) => console.error(error)}
                requestUrl={{
                    url:
                    'https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api',
                    useOnPlatform: 'web',
                }} // this in only required for use on the web. See https://git.io/JflFv more for details.
                keyboardShouldPersistTaps='always'
                styles={{
                    textInputContainer: {
                        width: "90%",
                        //top: 8,
                        alignSelf: 'center'
                    },
                    textInput: {
                        borderColor: grey,
                        borderWidth: 1,
                        borderRadius: 5,
                        height: 48,
                        paddingBottom: 8,
                        color: black,
                        fontSize: 16,
                    },
                    predefinedPlacesDescription: {
                        color: '#1faadb',
                    },
                }}
            />
</View>
        <View style={style.mapContainer}>
            <MapView 
                style={style.map} 
                region={region}
                onRegionChangeComplete={region => setRegion(region)}
            >
            <Marker coordinate={{ 
                latitude: latitude , 
                longitude: longitude, 
            }}></Marker>
            </MapView>
        </View>

I have tried other methods based on stackoverflow's answers but they seem to be outdated and I can't run them


Solution

  • To do this, first, you need to get the coordinates of the place you selected to use it as the coordinates where you want to set your region and marker when you press a place from the autocomplete suggestion. You can do this by adding the following code:

    GooglePlacesDetailsQuery={{
              fields: 'geometry',
            }}
    

    I also used the useState that I will use when changing the region and marker state after selecting the place.

    const [regionCoords, setRegion] = useState({ lat: 37.78825, lng: -122.4324 });
    const [marker, setMarker] = useState({ lat: 37.78825, lng: -122.4324 });
    

    Next, I set fetchDetails={true} since the coordinates from GooglePlacesDetailsQuery we used earlier will be displayed in the details property of the onPress property.

    On the onPress property, I call a function and set the state for region and marker from details property.

    Here's a sample code in snack where you need to set your own API key for the Autocomplete to work and the code snippet is shown below:

    import React, { useState, useEffect } from 'react';
    import { View, StyleSheet, TextInput, Dimensions } from 'react-native';
    import Constants from 'expo-constants';
    import { GooglePlacesAutocomplete } from 'react-native-google-places-autocomplete';
    import MapView, { Marker } from 'react-native-maps';
    const GOOGLE_PLACES_API_KEY = ''; // never save your real api key in a snack!
    var screenWidth = Dimensions.get('window').width;
    
    
    const App = () => {
      const [regionCoords, setRegion] = useState({ lat: 37.78825, lng: -122.4324 });
      const [marker, setMarker] = useState({ lat: 37.78825, lng: -122.4324 });
    
      const onPress = (data, details) => {
        setRegion(details.geometry.location);
        setMarker(details.geometry.location);
      };
    
      return (
        <View style={styles.container}>
          <MapView
            style={styles.map}
            region={{
              latitude: regionCoords.lat,
              longitude: regionCoords.lng,
              latitudeDelta: 0.0922,
              longitudeDelta: 0.0421,
            }}>
            <Marker coordinate={{ latitude: marker.lat, longitude: marker.lng }} />
          </MapView>
    
          <GooglePlacesAutocomplete
            styles={styles.searchbar}
            placeholder="Search"
            query={{
              key: GOOGLE_PLACES_API_KEY,
              language: 'en', // language of the results
            }}
            GooglePlacesDetailsQuery={{
              fields: 'geometry',
            }}
            fetchDetails={true}
            onPress={onPress}
            onFail={(error) => console.error(error)}
            requestUrl={{
              url:
                'https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api',
              useOnPlatform: 'web',
            }} // this in only required for use on the web. See https://git.io/JflFv more for details.
          />
        </View>
      );
    };
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
      },
      map: {
        left: 0,
        right: 0,
        top: 0,
        bottom: 0,
        position: 'absolute',
      },
      searchbar: {
        description: {
          fontWeight: 'bold',
        },
        predefinedPlacesDescription: {
          color: '#1faadb',
        },
        textInputContainer: {
          backgroundColor: 'rgba(0,0,0,0)',
          top: 50,
          width: screenWidth - 10,
          borderWidth: 0,
        },
        textInput: {
          marginLeft: 0,
          marginRight: 0,
          height: 38,
          color: '#5d5d5d',
          fontSize: 16,
          borderWidth: 0,
        },
        listView: {
          backgroundColor: 'rgba(192,192,192,0.9)',
          top: 23,
        },
      },
    });
    
    export default App;