Concepts / Building Search UI / Algolia Places
Jun. 07, 2019

Algolia Places

Overview

Algolia Places provides a fast, distributed, and easy way to use an address search autocomplete JavaScript library on your website. There is no built-in solution to integrate Algolia Places with React InstantSearch. But you can create a custom widget that will wrap Places. In this guide we will see how we can create a custom Places widget that interacts with the GeoSearch widget of React InstantSearch. You can find the complete source code of the example on GitHub.

Connector

The first step is to build our custom widget on top of Algolia Places, which involves creating a custom connector that will link Places to the React InstantSearch context. The refine function stores the value from the Places input under the aroundLatLng attribute. Then to apply our value to our search we leverage the aroundLatLng search parameter. At the same time we also clear insideBoundingBox currently applied because those two parameters are not “compatible”. When a bounding box is set, the aroundLatLng parameter is ignored.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import { createConnector } from 'react-instantsearch-dom';

export default createConnector({
  displayName: 'AlgoliaPlaces',

  getProvidedProps() {
    return {};
  },

  refine(props, searchState, nextValue) {
    return {
      ...searchState,
      aroundLatLng: nextValue,
      boundingBox: {},
    };
  },

  getSearchParameters(searchParameters, props, searchState) {
    const currentRefinement =
      searchState.aroundLatLng || props.defaultRefinement;

    return searchParameters
      .setQueryParameter('insideBoundingBox')
      .setQueryParameter(
        'aroundLatLng',
        `${currentRefinement.lat}, ${currentRefinement.lng}`
      );
  },
});

Widget

The second step (to build our custom widget on top of Algolia Places) is to create a React wrapper around the Algolia Places JS library. This wrapper component will also be wrapped by the connector that we created above. Keep in mind that it’s a very simple example. The widget doesn’t support all the Algolia Places options. Feel free to adapt it to your own needs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import React, { Component } from 'react';
import places from 'places.js';
import connect from './connector';

class Places extends Component {
  createRef = c => (this.element = c);

  componentDidMount() {
    const { refine, defaultRefinement } = this.props;

    const autocomplete = places({
      container: this.element,
      // Algolia Places options
    });

    autocomplete.on('change', event => {
      refine(event.suggestion.latlng);
    });

    autocomplete.on('clear', () => {
      refine(defaultRefinement);
    });
  }

  render() {
    return (
      <div style={{ marginBottom: 20 }}>
        <input
          ref={this.createRef}
          type="search"
          id="address-input"
          placeholder="Where are we going?"
        />
      </div>
    );
  }
}

export default connect(Places);

Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch } from 'react-instantsearch-dom';
import Places from './widget';

const searchClient = algoliasearch(
  'latency',
  '6be0576ff61c053d5f9a3225e2a90f76'
);

const App = () => (
  <InstantSearch indexName="airports" searchClient={searchClient}>
    <Places
      defaultRefinement={{
        lat: 37.7793,
        lng: -122.419
      }}
    />
  </InstantSearch>
);

You can find the complete source code of the example on GitHub.

Did you find this page helpful?