Street Address Form Validation with ReactJS and HERE Geocoder Autocomplete
Tags: react, geocoder, javascript
Published: 2021-02-23 23:02:17

---
title: Street Address Form Validation with ReactJS and HERE Geocoder Autocomplete
published: true
description: Solution to verify a street address with auto-complete as user is typing
tags: react,geocoder,javascript
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/0pdb2ry0y9ex69hkgnqv.png
canonical_url: https://developer.here.com/blog/street-address-validation-with-reactjs-and-here-geocoder-autocomplete
---
If you want customers to buy from you, requiring a shipping or billing address may become part of your ReactJS application. Nearly every database course looks at postal addresses as a good baseline tutorial for how to organize your data model in normal form, but what about on the client-side?

To keep garbage out of your records you may want to take some time to address this with address validation. If you also want to improve the user experience, the [HERE Geocoder Autocomplete API](https://developer.here.com/documentation/geocoder-autocomplete/topics/quick-start-get-suggestions.html) may help. This REST service lets you identify an address in fewer keystrokes which can help avoid spelling mistakes by providing suggestions with each character typed. There are also some powerful features like spatial and region filters to improve relevance as well.

# Project

For this project, we want to create a simple address form as shown by this mockup.

![Basic Mockup](https://dev-to-uploads.s3.amazonaws.com/i/a8az4r52yaxo5r3dhqfi.png)

As you start typing “2168 Sha” the rest of the address should be filled in automatically. We can then check the address with the [HERE Geocoder API](https://developer.here.com/documentation/geocoder/topics/quick-start-geocode.html) to be sure we can identify a latitude and longitude value.

# Getting Started

Generating 29,542 files for what amounts to a single page form may seem like overkill, but I still recommend starting with **create-react-app**. The development tools like a local server with live-reloading in a browser are helpful for quick iterations. Let’s get started by running the following:

```bash
create-react-app app
cd app
npm install bootstrap axios
npm start
```
As you can see I’ll also be using [Bootstrap](http://getbootstrap.com/) as the CSS framework and [axios](https://www.npmjs.com/package/axios) as an HTTP client.


# Thinking in React

Following the concepts from the ReactJS tutorial Thinking in React we will follow a few basic steps.

1. Break the UI into a component hierarchy
2. Build a static version
3. Identify the minimal representation of UI state
4. Identify where the state should live
5. Add inverse data flow

## Break the UI into a component hierarchy

Using our mockup from before, it looks like we can break the page up into a number of components.

![Component Labels](https://dev-to-uploads.s3.amazonaws.com/i/0pdb2ry0y9ex69hkgnqv.png)

## Build a static version

Starting from the bottom, the **AddressItem** is a single row item consisting of a label and form element. I’m using ES6 classes and exporting the class for use by other components.

```javascript 
import React, { Component } from 'react';

class AddressItem extends Component {
  render() {
    return (
        <div className="row form-group justify-content-start">
            <label className="col-sm-4 col-form-label">{this.props.label}</label>
            <div className="col-xl-8">
              <input
                type="text"
                defaultValue={this.props.value}
                onChange={this.props.onChange}
                className="form-control"
                placeholder={this.props.placeholder} />
            </div>
        </div>
      );
  }
}

export default AddressItem;

```

The **AddressSuggest** and **AddressInput** components both make use of the AddressItem in their render methods.

```javascript 
// app/src/AddressSuggest.js
class AddressSuggest extends Component {
  render() {
    return (
      <AddressItem label="Address" value={this.props.query} placeholder="start typing" />
      );
  }
}
```

You may recognize that I've skipped the import and exports here for brevity but they are still required.  You can find those in the full listing from the GitHub repository linked at the end.

```javascript 
// app/src/AddressInput.js
class AddressInput extends Component {
  render() {
    return (
      <div className="card"><div className="card-body">
      <AddressItem label="Street" value={this.props.street} placeholder="" readonly="true" />
      <AddressItem label="City" value={this.props.city} placeholder="" readonly="true" />
      <AddressItem label="State" value={this.props.state} placeholder="" readonly="true" />
      <AddressItem label="Postal Code" value={this.props.code} placeholder="" readonly="true" />
      <AddressItem label="Country" value={this.props.country} placeholder="" readonly="true" />
      </div></div>
    );
  }
}

```

Continuing up the hierarchy, the **AddressForm** combines the whole input form along with submission buttons to do our validation.

```javascript
// app/src/AddressForm.js
class AddressForm extends Component {
  render() {
    return (
        <div className="container">
          <AddressSuggest />
            query="4168 S"
            />
          <AddressInput
            street="4168 Shattuck Ave"
            city="Berkeley"
            state="CA"
            code="94704"
            country="USA"
            />
          <br/>
          <button type="submit" className="btn btn-primary">Check</button>
          <button type="submit" className="btn btn-outline-secondary">Clear</button>
        </div>
      );
  }
}

```

As you can see we just hard-coded some static values in as properties to see how our form will look before we need to deal with any interactive behaviors. Up next, we need to replace some of those properties with state.

## Tracking State

Up to this point we’ve only used immutable properties. Now we want to go back and start tracking state. The minimal information we want to track:

* search query entered by the user which changes over time
* postal address can be computed, but can also change over time by user input

The AddressForm is a common ancestor in the hierarchy for these two related components that we want to keep in sync. As the user starts typing text in the AddressSuggest we will query the HERE Geocoder Autocomplete API and update AddressInput.

Looking at the [HERE Autocompletion JavaScript Demo](https://developer.here.com/api-explorer/rest/geocoding_suggestions) we see the required parameters of query, `app_id`, and `app_code`. Unlike that demo, we will use axios as the HTTP client for making requests. The constant variables APP_ID_HERE and APP_CODE_HERE also need to be defined to be referenced as seen in the code below.

The AddressForm now looks like:


```javascript

class AddressForm extends Component {
  constructor(props) {
    super(props);

    const address = this.getEmptyAddress();
    this.state = {
      'address': address,
      'query': '',
      'locationId': ''
    }

    this.onQuery = this.onQuery.bind(this);
  }

  onQuery(evt) {
    const query = evt.target.value;
    if (!query.length > 0) {
      const address = this.getEmptyAddress();
      return this.setState({
        'address': address,
        'query': '',
        'locationId': ''
        })
    }

    const self = this;
    axios.get('https://autocomplete.geocoder.api.here.com/6.2/suggest.json', {
      'params': {
        'app_id': APP_ID_HERE,
        'app_code': APP_CODE_HERE,
        'query': query,
        'maxresults': 1,
      }}).then(function (response) {
        const address = response.data.suggestions[0].address;
        const id = response.data.suggestions[0].locationId;
        self.setState({
          'address': address,
          'query': query,
          'locationId': id,
          });
      });
  }

  render() {
    return (
      <div class="container">
        <AddressSuggest
          query={this.state.query}
          onChange={this.onQuery}
          />
        <AddressInput
          street={this.state.address.street}
          city={this.state.address.city}
          state={this.state.address.state}
          postalCode={this.state.address.postalCode}
          country={this.state.address.country}
          />
        ...
      );
  }
}

```

The response from the Geocoder Autocomplete includes an array of suggestions. Two valuable pieces of information there include the `locationId` if we wanted to do a full geocoder lookup by id to get the latitude and longitude. Included is also an `address` block which details the city, country, street, state, and postalCode for display in our form.

## Inverse Data Flow

You may have noticed that for our AddressSuggest component we added a `onChange={this.onQuery}`. This pushes this method down to lower-level components. Those lower level components need to respond to user input which should be easy now that we’ve passed a reference to this handler as a property as seen in the **AddressSuggest** component.

```javascript

return (
    <AddressItem
      label="Address"
      value={this.props.query}
      onChange={this.props.onChange}
      placeholder="start typing" />
);
```

It is worth noting that each character typed by the user triggers this event. Since each event fires off a request to the Geocoder Autocomplete service we can quickly rack up many transactions. A final solution may make more efficient use of how these events are handled or display a lookahead of more than one suggestion at a time by changing `maxresults=10`.

# Validation

Up to this point we’ve helped the user by using their input as suggestions for guessing the correct address with less typing and errors. Once the address is input though, now we want to check it. We need to implement the behavior of our check and clear buttons using the [HERE Geocoder](https://developer.here.com/documentation/geocoder/topics/quick-start-geocode.html).

First, let’s modify our rendered elements to include a result and `onClick` event callbacks.

```javascript
{ result }
<button type="submit" className="btn btn-primary" onClick={this.onCheck}>Check</button>
<button type="submit" className="btn btn-outline-secondary" onClick={this.onClear}>Clear</button>
```

We also make sure that all of our event handlers are bound in the constructor. This makes sure that `this` is an available reference. We then have methods defined for each of these cases.

```javascript

// User has entered something in address suggest field
this.onQuery = this.onQuery.bind(this);
// User has entered something in address field
this.onAddressChange = this.onAddressChange.bind(this);
// User has clicked the check button
this.onCheck = this.onCheck.bind(this);
// User has clicked the clear button
this.onClear = this.onClear.bind(this);
```

The clear handler is pretty straightforward, just calling `setState()` for returning everything to the initial state as it was when constructor originally runs. The check handler is much more involved. Let’s look at it in a few pieces. This first section is initializing the parameters for the Geocoder service. If we used the Geocoder Autocomplete to find a suitable address, we should already have a LocationId that we can use. If we don’t have that or the user entered text into the various fields – then we’ll construct a search string with whatever details are provided.

```javascript

onCheck(evt) {
  let params = {
    'app_id': APP_ID_HERE,
    'app_code': APP_CODE_HERE
  }

  if (this.state.locationId.length > 0) {
    params['locationId'] = this.state.locationId;
  } else {
    params['searchtext'] = this.state.address.street
      + this.state.address.city
      + this.state.address.state
      + this.state.address.postalCode
      + this.state.address.country
  }
  ...
}

```

With the parameters in place, we again use axios to fetch a response from the geocoder REST API. If we get back a promised response with a matching location we can set the state to the appropriate success or error conditions.

```javascript

onCheck(evt) {
  ...

  const self = this;
  axios.get('https://geocoder.api.here.com/6.2/geocode.json',
    { 'params': params }
  ).then(function(response) {
    const view = response.data.Response.View
    if (view.length > 0 && view[0].Result.length > 0) {
      const location = view[0].Result[0].Location;

      self.setState({
        'isChecked': 'true',
        'coords': {
            'lat': location.DisplayPosition.Latitude,
            'lon': location.DisplayPosition.Longitude
        },
        'address': {
          'street': location.Address.HouseNumber + ' ' + location.Address.Street,
          'city': location.Address.City,
          'state': location.Address.State,
          'postalCode': location.Address.PostalCode,
          'country': location.Address.Country
        }});
    } else {
      self.setState(
        'isChecked': true,
        'coords': null
        );
    }

  })
  ...
}

```

Getting a latitude and longitude alone is not the best indicator so it is also important to look at the MatchLevel, MatchType, and MatchQuality to evaluate whether the address is valid.

```javascript
 
"Result": [
          {
            "Relevance": 1,
            "MatchLevel": "houseNumber",
            "MatchQuality": {
              "State": 1,
              "City": 1,
              "Street": [
                1
              ],
              "HouseNumber": 1
            },
            "MatchType": "pointAddress",
            ...

```

You can learn more about the address details like this from the [Geocoder Search Response](https://developer.here.com/documentation/geocoder/topics/resource-type-response-geocode.html) documentation.

For the full source listing, please review the GitHub repository [HERE-react-address-validation](https://github.com/j12y/HERE-react-address-validation).

![animated gif](https://cdn2.hubspot.net/hubfs/2174253/geocoder-autocomplete.gif)

# Summary

This demonstration looked into how to think about creating components with React so that we could build a smart address form with the HERE Geocoder Autocomplete API . We also did some additional validation using the HERE Geocoder API to retrieve a latitude and longitude to help us test our match quality.  Street address validation for deliverability can be a complex subject but hope this gets you started.

There are many other ways to do client-side address validation which haven’t been covered here but hope that seeing how to use a Geocoder as a component can be valuable for better user experience. If you use other libraries like [Formik](https://github.com/jaredpalmer/formik), [react-final-form](https://github.com/final-form/react-final-form) or [informed](https://github.com/joepuzzo/informed) and have other ideas about how to do address validation with React let me know in the comments.