Learn fetching address details using Google addresses API (Zipcode or postcode, City, State, Country, Full address) using React js and Formik & Material UI fields with autocomplete suggestions

Auto complete Google addresses API (Reactjs, Material UI, Formik)

Written By: Mohamed Atef

Published: 2021-07-03 | Comments: 3 | Category: React js

Google addresses API with React js 

What is Google Maps JavaScript API?

Google Maps or addresses API is a service from Google Could PlatformWhich allow you to get the key and start searching or fetching data and details about places or addresses using google, and I am going to show you how to use this service with React js, Formik, Material UI

Setup Google addresses API with React js

In the beginning, I searched and tried a lot of Packages but for sorry around 90% of the packages are not supporting Material UI and it's not gonna be simple to use it with Formik so I created a custom way to figure it out, it's really simple, let's start setting up the google places API all you need to do is just getting your project key, From Google Maps Click on enable  

Then from Credentials > Create Credentials and choose API, 

When you finish this step google will ask you to copy your API key copy it and do the next step 

Start working with React js

You need to load the library of google places into your website, we gonna do this from the App folder > public > index.html then add this script at the end of the head tag

<script type=text/javascript src=//maps.googleapis.com/maps/api/js?key=YOUR_KEY_HERE&language=en&libraries=places></script>

Now you need to make sure that you installed Formik & Material UI & Material Lab 

Install them in case you don't have them

npm install @material-ui/core

Install Formik

 npm install formik --save

Material UI Lab (to import the Autocomplete input)  

npm install @material-ui/lab

Now you need to set up two components include Google functions to make it easy to use them in the parent component 

First file: GoogleAutoCompelete.js

const GoogleAutoCompelete = async text => new Promise((resolve, reject) => { if (!text) { return reject("Need valid text input") } // for use in things like GatsbyJS where the html is generated first if (typeof window === "undefined") { return reject("Need valid window object") } try { new window.google.maps.places.AutocompleteService().getQueryPredictions( { input: text, componentRestrictions: { country: "us" }, fields: ["address_components", "geometry"], }, resolve ) } catch (e) { reject(e) } })export default GoogleAutoCompelete;

Second file: GetPostalCode.js

const GetPostalCode = async placeId => new Promise((resolve, reject) => { if (!placeId) reject("placeId not provided") try { new window.google.maps.places.PlacesService( document.createElement("div") ).getDetails( { placeId, fields: ["address_components"], }, details => { return resolve(details) } ) } catch (e) { reject(e) } })export default GetPostalCode;

Then you have to include them in the main component 

import GoogleAutoCompelete from './Google/GoogleAutoCompelete';import GetPostalCode from './Google/GetPostalCode';

Now create the form with the functions to use the components 

 <Formik enableReinitialize={true} initialValues={{ companyAddress: '', zipCode: '', city: '', stateOfAddress: '', submit: null }} validationSchema={Yup.object().shape({ companyAddress: Yup.string().max(255).required('Company address is required'), zipCode: Yup.string().max(255), city: Yup.string().max(255), stateOfAddress: Yup.string().max(255), })} onSubmit={async (values, { setErrors, setStatus, setSubmitting, }) => { try { console.log(values); } catch (err) { console.error(err); setStatus({ success: false }); setErrors({ submit: err.message }); setSubmitting(false); } }} > {({ errors, handleBlur, handleChange, handleSubmit, isSubmitting, touched, values, setFieldValue }) => ( <form onSubmit={handleSubmit} {...rest} > <Grid container> <Grid item md={6} xs={12}> <Box mt={3} px={6}> <Grid container spacing={3}> <Grid item xs={12}> <Autocomplete options={addresses.map((option) => option.description)} // closeIcon= { () => { return; } } onInputChange={(event, value) => { changeAddress(value, setFieldValue); }} autoComplete={false} renderInput={(params) => ( <TextField {...params} label="Company Address" name=companyAddress value={values.companyAddress} onChange={(value) => { handleChangeAddress(value); }} variant="outlined" /> )} /> </Grid> <Grid item xs={12}> <TextField error={Boolean(touched.zipCode && errors.zipCode)} fullWidth helperText={touched.zipCode && errors.zipCode} label="Zip Code" name=zipCode onBlur={handleBlur} onChange={handleChange} value={values.zipCode} variant="outlined" /> </Grid> <Grid item xs={12}> <TextField error={Boolean(touched.city && errors.city)} fullWidth helperText={touched.city && errors.city} label="City" name=city onBlur={handleBlur} onChange={handleChange} value={values.city} variant="outlined" /> </Grid> <Grid item xs={12}> <TextField error={Boolean(touched.stateOfAddress && errors.stateOfAddress)} fullWidth helperText={touched.stateOfAddress && errors.stateOfAddress} label="State (Administrative Area)" name=stateOfAddress onBlur={handleBlur} onChange={handleChange} value={values.stateOfAddress} variant="outlined" /> </Grid> </Grid> {Boolean(touched.tags && errors.tags) && ( <Box mt={2}> <FormHelperText error> {errors.tags} </FormHelperText> </Box> )} {Boolean(touched.startDate && errors.startDate) && ( <Box mt={2}> <FormHelperText error> {errors.startDate} </FormHelperText> </Box> )} {Boolean(touched.endDate && errors.endDate) && ( <Box mt={2}> <FormHelperText error> {errors.endDate} </FormHelperText> </Box> )} </Box> <Box mt={12} display="flex" > <Box flexGrow={1} /> <Button color="secondary" disabled type=submit variant="contained" size="large" > Submit </Button> </Box> </Grid> </Grid> </form> )} </Formik>

All we need to use the Google components 

 const [addresses, setAddresses] = useState([]); const handleChangeAddress = async (searchValue) => { const results = await GoogleAutoCompelete(searchValue.target.value); if (results) { setAddresses(results); } } const changeAddress = async (value, setFieldValue) => { let result = null; for(let x = 0; x < addresses.length; x++){ if(value === addresses[x].description){ result = await GetPostalCode(addresses[x].place_id); // Get Zip code } } if(!result){ return ; } setFieldValue('companyAddress', value); let postcode = null; for(let i = 0; i < result.address_components.length; i++){ if(result.address_components[i].types[0] === 'postal_code'){ postcode = result.address_components[i].long_name; } } setFieldValue('zipCode', postcode); // Get city let city = null; for(let i = 0; i < result.address_components.length; i++){ if(result.address_components[i].types[0] === 'locality'){ city = result.address_components[i].long_name; } } if(!city){ for(let i = 0; i < result.address_components.length; i++){ if(result.address_components[i].types[0] === 'administrative_area_level_2'){ city = result.address_components[i].long_name; } } } setFieldValue('city', city); // Get State let state = null; for(let i = 0; i < result.address_components.length; i++){ if(result.address_components[i].types[0] === 'administrative_area_level_1'){ state = result.address_components[i].long_name; } } if(!state){ for(let i = 0; i < result.address_components.length; i++){ if(result.address_components[i].types[0] === 'administrative_area_level_2'){ state = result.address_components[i].long_name; } } } setFieldValue('stateOfAddress', state); }

That's all and here is the content of the main component (AutoFillForm.js)

import React, { useState, useEffect } from 'react';import * as Yup from 'yup';import { Formik } from 'formik';import { Box, Button, FormHelperText, Grid, TextField,} from '@material-ui/core';import Autocomplete from '@material-ui/lab/Autocomplete';import GoogleAutoCompelete from './Google/GoogleAutoCompelete';import GetPostalCode from './Google/GetPostalCode';const AutoFillForm = ({ className, setData, data, projectId, ...rest}) => { const [addresses, setAddresses] = useState([]); const handleChangeAddress = async (searchValue) => { if(!searchValue.target.value){ return null; } const results = await GoogleAutoCompelete(searchValue.target.value); if (results) { setAddresses(results); } } const changeAddress = async (value, setFieldValue) => { let result = null; for(let x = 0; x < addresses.length; x++){ if(value === addresses[x].description){ result = await GetPostalCode(addresses[x].place_id); // Get Zip code } } if(!result){ return ; } setFieldValue('companyAddress', value); let postcode = null; for(let i = 0; i < result.address_components.length; i++){ if(result.address_components[i].types[0] === 'postal_code'){ postcode = result.address_components[i].long_name; } } setFieldValue('zipCode', postcode); // Get city let city = null; for(let i = 0; i < result.address_components.length; i++){ if(result.address_components[i].types[0] === 'locality'){ city = result.address_components[i].long_name; } } if(!city){ for(let i = 0; i < result.address_components.length; i++){ if(result.address_components[i].types[0] === 'administrative_area_level_2'){ city = result.address_components[i].long_name; } } } setFieldValue('city', city); // Get State let state = null; for(let i = 0; i < result.address_components.length; i++){ if(result.address_components[i].types[0] === 'administrative_area_level_1'){ state = result.address_components[i].long_name; } } if(!state){ for(let i = 0; i < result.address_components.length; i++){ if(result.address_components[i].types[0] === 'administrative_area_level_2'){ state = result.address_components[i].long_name; } } } setFieldValue('stateOfAddress', state); }//We can use this function to disable the browser auto complete from the fields because it looks really annoying useEffect(() => { window.document.querySelector('input[name="companyAddress"]').setAttribute('autocomplete', 'disable'); window.document.querySelector('input[name="companyAddress"]').setAttribute('aria-autocomplete', 'off'); window.document.querySelector('input[name="zipCode"]').setAttribute('autocomplete', 'disable'); window.document.querySelector('input[name="zipCode"]').setAttribute('aria-autocomplete', 'off'); window.document.querySelector('input[name="city"]').setAttribute('autocomplete', 'disable'); window.document.querySelector('input[name="city"]').setAttribute('aria-autocomplete', 'off'); window.document.querySelector('input[name="stateOfAddress"]').setAttribute('autocomplete', 'disable'); window.document.querySelector('input[name="stateOfAddress"]').setAttribute('aria-autocomplete', 'off'); }, []); return ( <Formik enableReinitialize={true} initialValues={{ companyAddress: '', zipCode: '', city: '', stateOfAddress: '', submit: null }} validationSchema={Yup.object().shape({ companyAddress: Yup.string().max(255).required('Company address is required'), zipCode: Yup.string().max(255), city: Yup.string().max(255), stateOfAddress: Yup.string().max(255), })} onSubmit={async (values, { setErrors, setStatus, setSubmitting, }) => { try { console.log(values); } catch (err) { console.error(err); setStatus({ success: false }); setErrors({ submit: err.message }); setSubmitting(false); } }} > {({ errors, handleBlur, handleChange, handleSubmit, isSubmitting, touched, values, setFieldValue }) => ( <form onSubmit={handleSubmit} {...rest} > <Grid container> <Grid item md={6} xs={12}> <Box mt={3} px={6}> <Grid container spacing={3}> <Grid item xs={12}> <Autocomplete options={addresses.map((option) => option.description)} // closeIcon= { () => { return; } } onInputChange={(event, value) => { changeAddress(value, setFieldValue); }} autoComplete={false} renderInput={(params) => ( <TextField {...params} label="Company Address" name=companyAddress value={values.companyAddress} onChange={(value) => { handleChangeAddress(value); }} variant="outlined" /> )} /> </Grid> <Grid item xs={12}> <TextField error={Boolean(touched.zipCode && errors.zipCode)} fullWidth helperText={touched.zipCode && errors.zipCode} label="Zip Code" name=zipCode onBlur={handleBlur} onChange={handleChange} value={values.zipCode} variant="outlined" /> </Grid> <Grid item xs={12}> <TextField error={Boolean(touched.city && errors.city)} fullWidth helperText={touched.city && errors.city} label="City" name=city onBlur={handleBlur} onChange={handleChange} value={values.city} variant="outlined" /> </Grid> <Grid item xs={12}> <TextField error={Boolean(touched.stateOfAddress && errors.stateOfAddress)} fullWidth helperText={touched.stateOfAddress && errors.stateOfAddress} label="State (Administrative Area)" name=stateOfAddress onBlur={handleBlur} onChange={handleChange} value={values.stateOfAddress} variant="outlined" /> </Grid> </Grid> {Boolean(touched.tags && errors.tags) && ( <Box mt={2}> <FormHelperText error> {errors.tags} </FormHelperText> </Box> )} {Boolean(touched.startDate && errors.startDate) && ( <Box mt={2}> <FormHelperText error> {errors.startDate} </FormHelperText> </Box> )} {Boolean(touched.endDate && errors.endDate) && ( <Box mt={2}> <FormHelperText error> {errors.endDate} </FormHelperText> </Box> )} </Box> <Box mt={12} display="flex" > <Box flexGrow={1} /> <Button color="secondary" disabled type=submit variant="contained" size="large" > Submit </Button> </Box> </Grid> </Grid> </form> )} </Formik> );};export default AutoFillForm;

If you have any questions let me know in the comments below 
Thanks

Comments

Leave a comment

Join us

Join our community and get the chance to solve your code issues & share your opinion with us

Sign up Now

Related posts

CSS media query (breakpoints) in Material UI
Publish date: 2021-10-21 | Comments: 0

Tag: React js

Deploy Reactjs using Azure
Publish date: 2021-07-31 | Comments: 0

Tag: React js

Display PDF in Reactjs from Authenticated API
Publish date: 2022-02-14 | Comments: 0

Tag: React js

Hide errors in live website Reactjs
Publish date: 2022-03-31 | Comments: 0

Tag: React js

How to sort arrays in Reactjs?
Publish date: 2022-08-05 | Comments: 1

Tag: React js