Code Monkey home page Code Monkey logo

mui-places-autocomplete's Introduction

MUIPlacesAutocomplete

Build Status

Preview

Features

  • Easy-to-use component for searching for places
  • Place suggestions displayed in realtime
  • Input state can be controlled externally
  • Promise based geocoding utility functions (latitude/longitude)
  • Google Material Design styling provided by Material-UI (v1)
  • Safe to render on the server (SSR)
  • Integrates with other 3rd party libraries (e.g. Redux Form)
  • Thoroughly tested

Installation

To install this component run the following command:

yarn add mui-places-autocomplete --ignore-scripts

or

npm install mui-places-autocomplete --save --ignore-scripts

Note that if you exclude the --ignore-scripts option when installing a package then the prepublish script in package.json is ran after installing locally. Tests are ran as part of the prepublish script and they will fail if you haven't yet set a Google API key to the enivronment variables GOOGLE_API_KEY or GOOGLE_API_TEST_KEY (see setup section).

Demo

Note that you must have followed the setup steps to run the demo as it depends on services provided by Google.

To see a demo of this component locally clone this repository and run:

yarn demo

or

npm run demo

Usage

import React from 'react'
import SomeCoolComponent from 'some-cool-component'
import MUIPlacesAutocomplete from 'mui-places-autocomplete'

class Example extends React.Component {
  constructor() {
    super()

    this.onSuggestionSelected = this.onSuggestionSelected.bind(this)
  }

  onSuggestionSelected(suggestion) {
    // Add your business logic here. In this case we just log...
    console.log('Selected suggestion:', suggestion)
  }

  render() {
    // Use 'renderTarget' prop to render a component/target we want the suggestions to popover

    return (
      <MUIPlacesAutocomplete
        onSuggestionSelected={this.onSuggestionSelected}
        renderTarget={() => (<SomeCoolComponent />)}
      />
    )
  }
}

export default Example

Advanced Usage

  • DemoControlledInput.jsx - Example that shows how to control the <input> element as well as integrate with Redux Form.
  • DemoGeocodeLatLong.jsx - Example that shows how to obtain the latitude/longitude of a selected suggestion.

Setup

This component relies on some basic setup before usage. It makes use of services provided by Google. To properly make use of the services you will need to do three things:

  1. Enable the Google Places API Web Service
  2. (Optional) Enable the Google Maps Geocoding API (only required if making use of the geocoding utility functions)
  3. Enable the Google Maps JavaScript API
  4. Obtain a Google API key

You can do all of these things from your Google developers console here: https://console.developers.google.com

The component relies on the Places library in the Google Maps JavaScript API. To load the Places library on the client you must add the following to the HTML document you deliver to your clients:

<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places"></script>

Be sure that you replace YOUR_API_KEY with the one you just created or obtained previously.

This component also has testing which makes use of the Places library in the Google Maps JavaScript API. Rather than loading the Places library it uses a module provided by Google. It also requires an API key. This key can be provided to a file @ test/api-key.js. If you would like it can also be provided as an environment variable named GOOGLE_API_KEY or GOOGLE_API_TEST_KEY.

Props

Prop Type Required Description
onSuggestionSelected Function Callback that provides the selected suggestion.
renderTarget Function Renders the components/elements that you would like to have the list of suggestions popover.
createAutocompleteRequest Function Returns an object that modifies which suggestions are shown to the user.
textFieldProps Object Props that will be spread onto a <TextField> MUI component that is responsible for rendering the <input> element. If you would like to control the state of the <input> element externally you must set the value key on the object passed to textFieldProps.

onSuggestionSelected (required)

This function will be called everytime a user has selected a suggestion. It has the following signature:

function onSuggestionSelected(suggestion)

renderTarget (required)

This function is invoked during rendering. It ought to return the components/elements that you want the list of suggestions to render (pop) over.

createAutocompleteRequest

<MUIPlacesAutocomplete> leverages the Google Places API Web Service to provide place suggestions that a user may select from based on the users input. The requests made to the Google Places API Web Service are very simple by default. This results in a wider breadth in the types of suggestions (i.e. an establishment, city/locality, specific address, etc.) returned when the user first starts searching for a place. The set of returned suggestions may also not be geospatially tight ("close to each other"). As the users search becomes more specific the types of suggestions returned start to narrow as well as tighten geospatially around each other.

Depending on your use case you may wish to:

  • Specify (i.e. narrow) the types of suggestions returned by the Google Places API Web Service
  • Bias/restrict the suggestions returned by the Google Places API Web Service to a specific area

You can achieve this by providing a function to the createAutocompleteRequest prop. The function is called everytime a request for suggestions is made to the Google Places API Web Service. The function passed to the createAutocompleteRequest prop ought to have the following signature:

function createAutocompleteRequest(inputValue)

Where:

  • inputValue - The users current search value

It ought to return an object that specifies what suggestions (i.e. types and bias/area restrictions) should be returned by the Google Places API Web Service. For example:

function createAutocompleteRequest(inputValue) {
  // Restrict the returned suggestions to those that:
  // 1) Are in Bellingham (latitude 48.7519, longitude 122.4787)
  // 2) Are within ~3 miles (5000 meters)
  // 3) Have an address associated with them
  return {
    input: inputValue,
    types: ['address'],
    location: { lat: () => 48.7519, lng: () => 122.4787 },
    radius: 5000,
  }
}

The properties that are allowed on the returned object are documented here: AutocompleteRequest API object specification

Note: There is no validation for what is returned from the function provided to the createAutocompleteRequest prop. So if you don't return an object or set the properties incorrectly then things are going to go poorly.

textFieldProps

A MUI <TextField> component is used to render the <input> element. It can be customized to meet your needs by supplying an object to the textFieldProps prop. All properties on the object supplied to the textFieldProps prop will be spread onto the <TextField> component. You can read more about the props that the <TextField> component accepts here: <TextField> API documentation

textFieldProps.value <input> control prop

To help meet your needs the state of the <input> element can be controlled externally. It is also useful if you would like to integrate <MUIPlacesAutocomplete> with other 3rd party libraries such as Redux Form. To control the state of the <input> element you must set the value property on the object passed to the textFieldProps prop.

// 'getState()' can return state from a React component, your app (e.g via Redux), some other source, etc.
const { inputValue } = getState()

<MUIPlacesAutocomplete textFieldProps={{ value: inputValue }} />

If you would like to have consistency between the controlled <input> elements state as well as any suggestions that are selected then you need to update the controlled state of the <input> element when a suggestion is selected. There is an example of how to do this in the advanced usage section.

Geocoding utility functions (latitude/longitude)

<MUIPlacesAutocomplete> is focused on providing functionality for searching for places of interest and providing realtime suggestions to searches. To accomplish this <MUIPlacesAutocomplete> leverages the Google Places API Web Service to provide place suggestions. The place suggestions returned by the Google Places API Web Service doesn't include any geospatial data (i.e. latitude/longitude). Depending on your use case you may require geospatial data about the suggestions.

To facilitate consumers of <MUIPlacesAutocomplete> and their different use cases, geocoding utility functions have been packaged together with the <MUIPlacesAutocomplete> component. Geocoding will allow you to convert addresses into geospatial data/coordinates such as latitude and longitude. For a complete demo showing how to use the geocoding utility functions see the advanced usage section.

Note: To make use of the geocoding utility functions you must enable the Google Maps Geocoding API. For more info see the setup section.

geocodeByPlaceID

Each suggestion returned to <MUIPlacesAutocomplete> by the Google Places API Web Service has a property named place_id. The place_id property contains a value that uniquely identifies a place in the Google Places database. The place_id property can be used in conjunction with the geocodeByPlaceID() function to get geospatial data for any suggestion.

The geocodeByPlaceID() function has the following signature:

function geocodeByPlaceID(placeId)

Where:

  • placeId - Unique identifier for a place in the Google Places database

The geocodeByPlaceID() function returns a promise that contains the results of the request made with the Google Maps Geocoding API.

import React from 'react'
import SomeCoolComponent from 'some-cool-component'
import MUIPlacesAutocomplete, { geocodeByPlaceID } from 'mui-places-autocomplete'

class Example extends React.Component {
  constructor() {
    super()

    // Setup your state here...
    this.state = { coordinates: null }

    this.onSuggestionSelected = this.onSuggestionSelected.bind(this)
  }

  onSuggestionSelected(suggestion) {
    geocodeByPlaceID(suggestion.place_id).then((results) => {
      // Add your business logic here. In this case we simply set our state with the coordinates of
      // the selected suggestion...

      // Just use the first result in the list to get the geometry coordinates
      const { geometry } = results[0]

      const coordinates = {
        lat: geometry.location.lat(),
        lng: geometry.location.lng(),
      }

      this.setState({ coordinates })
    }).catch((err) => {
      // Handle any errors that occurred when we tried to get geospatial data for a selected
      // suggestion...
    })
  }

  render() {
    // Your render logic here...
  }
}

export default Example

The properties that are returned on the array of geocode results are documented here: GeocodeResult API object specification

geocodeBySuggestion

The geocodeBySuggestion() function is a wrapper around the geocodeByPlaceID() function. It has the following signature:

function geocodeBySuggestion(suggestion)

Where:

  • suggestion - Object representing a suggestion returned by the Google Places API Web Service which has a property named place_id that uniquely identifies a place in the Google Places database.

It has the same behavior as the geocodeByPlaceID() function where it returns a promise that contains the results of the request made with the Google Maps Geocoding API.

Feedback

This was my first open-source project that I undertook while I was teaching myself full-stack development (JS (ES6)/HTML/CSS, Node, Express, NoSQL (DynamoDB), GraphQL, React, Redux, Material-UI, etc.). I'm very interested in taking feedback to either improve my skills (i.e. correct errors :)) or to make this component more useful in general/for your use case. Please feel free to provide feedback by opening an issue or messaging me.

References

License

MIT

mui-places-autocomplete's People

Contributors

giners avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

mui-places-autocomplete's Issues

<input> element ought to be controllable

The <input> element that is rendered ought to be controllable externally. This will allow <MUIPlacesAutocomplete> to meet an expanded breadth of use cases. An example of one use case would be allowing <MUIPlacesAutocomplete> to integrate with Redux Form.

Investigate/leverage packages/modules that load Google Maps lib/API

Consuming 3rd party libraries that are expected to be loaded in the browser/window properly is generally hard (why?). We ought to look into if there are any packages/modules that have done this and it would be an improvement to use the packages/modules over doing the work ourselves.

If there is a package/module that is an improvement (what would make it an improvement?) we ought to look to leverage it in our component.

Here is a module that we can look into as a starting point:

Here is a module that provides React Google Map components and we can look into what they did:

Investigate/leverage packages/modules that load Google Maps lib/API asdf

Google logo doesn't render

The dropdown the displays suggestions ought to render the Google logo. It currently doesn't.

When doing some visual debugging with Google Chrome developer tools it appears that the <img> element that is responsible for rendering the Google logo is in fact present/rendered. Yet the size (height/width) of the logo is 0. It looks as if it is trying to deliver the logos content directly from my server (e.g. http://somecoolproduct.com/12352062868230489) and I haven't actually made the logo available from that directory.

Further technical work/documentation is needed to make it so that the Google logo is rendered properly.

Manipulate suggestion rendering?

hi there @Giners

Is there a way to manipulate the suggestion text? For example as is, the component might return a list of suggestions like so
town name A, Victoria, Australia
town name B, Victoria, Australia
town name C, Victoria, Australia

Whereas for brevity I'd prefer
town name A, VIC
town name B, VIC

I'm thinking of a callback where, I could manipulate how the result returned from the Google API, is represented as a string.

I don't see a way to do that? As I understand createAutocompleteRequest is about controlling what Google returns, rather than how the component displays it.

Not showstopper but a nice to have.
Thank you

Update dependencies

The dependencies that MUI uses haven't been updated in a while. This task is to track the work required to update them. At a minimum the dependencies and peer dependencies ought to be updated.

Make background of suggestions non-transparent

I'm working with this component right now, and I don't know if I'm missing something obvious, but the background for the suggestions is transparent. I've tried rendering divs, and boxes in the render target, but nothing seems to be doing it. Here is my code:

<MUIPlacesAutocomplete
    onSuggestionSelected={this.handlePlaceSelect}
    renderTarget={() => (<div/>)}
    textFieldProps={
    {   
      variant: "outlined", 
      fullWidth: true, 
      label: "Street Address",
      autoComplete: "none",
     }
    }
/>

Here is a picture of the problem:
image

Here is what it normally looks like:
image

It seems to be blocking the outline of the lower input boxes, but not the label.
Any ideas?

Bug: Suggestions container has height set

The suggestions container has the height set to 200 pixels. This is causing the <MUIPlacesAutocomplete> component to take up unnecessary space when the suggestions container isn't being rendered as seen by this picture:

image

This ought to be fixed so that it no longer takes up unnecessary space when the suggestions container isn't being rendered.

Provide fine grained control over the appearance of <MUIPlacesAutocomplete>

<MUIPlacesAutocomplete> composes several elements/components to provide the functionality/appearance that it does. Consumers should be able to modify the functionality/appearance of <MUIPlacesAutocomplete> and in a way that is consistent with how Material-UI works (see https://material-ui-next.com/customization/overrides/) to meet their business needs/requirements.

My first thought is to using styling techniques. These resources can be used as starting points for providing a solution:

This request was inspired by the discussions in #28.

Use 'peerDependencies' avoid duplicating modules

While incorporating the <MUIPlacesAutocomplete> component into another project of mine I was experiencing errors as mentioned in MUI issue mui/material-ui#8742. Specifically during SSR I was seeing the following warnings:

Warning: Failed context type: Invalid context `64a55d578f856d258dc345b094a2a2b3` of type `Jss` supplied to `Component`, expected instance of `Jss`.
Warning: Failed context type: Invalid context `d4bd0baacbc52bbd48bbb9eb24344ecd` of type `SheetsRegistry` supplied to `Component`, expected instance of `SheetsRegistry`.

After reading the MUI issue I was able to resolve the issue by upgrading the MUI dependency in this project/package/module to match the version I use in my other project (MUI v1.0.0-beta.21) (commit: ebc0891). Yet I don't think/know if this is the correct approach to take long term. Especially as it may affect others who also use this project/package/module.

After reading more about the MUI issue previously mentioned it seems like that it might be better to setup peer dependencies for our project/package/module. This task is to learn more about what peer dependencies are and see if it using them is useful/will help us avoid this problem in the future. I'm presuming we would take one on MUI, if any, but there may be others.

Bug: Suggestions container doesn't render over (popover) elements

When the suggestions container of the component is rendered it doesn't render (popover) elements as seen in by this picture:
muiplacesautocomplete-popover-bug

The result is that when the suggestions are rendered they appear to "blend" in with rendered elements of the same "depth". Also focus/events aren't handled properly as the DOM isn't sure if we want to focus/receive events on the suggestions container/suggestions themselves or the elements sharing the same "depth" as the suggestions container/suggestions.

This ought to be fixed so that the suggestions container is rendered over elements. The elements that it is rendered over shouldn't be visible and not able to receive any focus/events until the suggestions container is no longer being rendered over said elements.

How to style the suggestion popup

G'day,

I'm trying to use this component, but when I render it the popup appears to take the entire window width rather than conforming to the enveloping div. Here's what it looks like rendered...

image

Any hints on whether this is a bug or is there a prop somewhere I can tweak to rest the style?

Feature: Allow for greater control over suggestions returned by Google

Currently the suggestions provided by the Google Places API Web Service have a wide breadth in the types of suggestions (i.e. an establishment, city/locality, specific address, etc.) returned when the user first starts searching for a place. The set of returned suggestions may also not be geospatially tight ("close to each other"). As the users search becomes more specific the types of suggestions returned start to narrow as well as tighten geospatially around each other. This is due to the fact that the request made to the Google Places API Web Service is unassuming and simply provides the users search input. This doesn't provide flexibility for meeting the use cases of those that consume <MUIPlacesAutocomplete>.

Consumers of <MUIPlacesAutocomplete> may have specific use cases in mind for their customers where they may want to:

  • Specify (i.e. narrow) the types of suggestions returned by the Google Places API Web Service
  • Bias/restrict the suggestions returned by the Google Places API Web Service to a specific area

This is a feature request to allow for more control over the suggestions returned by the Google Places API Web Service.

Bug: Can't set the 'id' value/prop on the <input> element

The docs say that the textFieldProps prop can be used to spread props onto the <TextField> component which is responsible for rendering the <input> element. See here: https://github.com/Giners/mui-places-autocomplete#textFieldProps

Per the Material-UI docs it says that providing the id prop will set the value of id on the rendered <input> element. See here: https://material-ui-next.com/api/text-field/

This doesn't appear to be working. Take this code snippet:

<MUIPlacesAutocomplete textFieldProps={{ id: 'my-cool-input-id' }} />

The value of id on the rendered <input> element is actually equal to mui-places-autocomplete-input and not my-cool-input-id.

how to remove input underline

i want to remove underline from MUIPlacesAutocomplete . using prop disableUnderline: true, but its not working. can you please tell me the solution?

@material-ui/core@"^1.0.0"

Hello I have this issue when I install a project that use @material-ui/core@"4.9.14 for the front end.

I want to use mui-places-autocomplete on my project and I have this issue:

Capture d’écran 2020-11-26 à 10 34 57

is it possible to update mui-places-autocomplete to use the last version of @material-ui/core ? how to do it ?

Thanks for your help

Set 'z-index' to render suggestions over descendant elements/components of <MPA>

Hi there,

First, thank you for this amazing library. Great work there.

My submit button comes from a different component and I'd like the autosuggest component to not know about it. Yet, by default, the suggestions show up below this button:

image

It would be great to have a way to customize the classes of the components inside MUIPlacesAutocomplete, including the suggestions box.

Latitude / Longitude data in returned object?

Hi there,

Love the component; it meets all but one of my requirements, as I will explain. I've been looking for something to replace React GeoSuggest. Feature wise React GeoSuggest is perfect, but its just not MUI friendly.

Latitude / Longitude?

It's just come to my attention that mui-places-autocomplete does not include Lat / Lng data for the selected suggestion. This is a deal-breaker for me; Lat Lng is really the only data I actually need.

React GeoSuggest provides this data, which is super useful. I wonder if this explains why their component assumes the user's API Key also has access to the Google Maps Geocoding API?

Would you consider adding such a feature?

Love your work.
Thanks

Feature: Callback when suggestion selected

The <MUIPlacesAutocomplete> component ought to provide a callback for when a suggestion is selected. This is important functionality that is missing as without it consumers have to modify/hack the <MUIPlacesAutocomplete> component themselves to figure out which suggestion was selected. I guess we shouldn't have released without this functionality and this was an oversight of mine.

This callback ought to be passed as a prop to the <MUIPlacesAutocomplete> component.

Bug: Uncaught TypeError: Cannot read property 'description' of null when focus lost

When rendering suggestions for the first time, if you click somewhere to cause focus to be lost (i.e. not the <input> element or the rendered suggestions container) then you will receive the following error: Uncaught TypeError: Cannot read property 'description' of null. This happens in the method we pass to the itemToString prop for the <Downshift> component.

Again, note that this only happens if a suggestion hasn't yet been selected. If you select a suggestion and then render suggestions and click somewhere to cause focus to be lost you don't experience this problem.

Publish new version w/ updated prop-types to remove fbjs dependency?

I have a project in which I'm not importing fbjs today. Indeed, in the latest prop-types, they don't use it either - see https://github.com/facebook/prop-types/blob/953ed9beb0f15498cd7e6e25c90f7cadd5f2149a/CHANGELOG.md#1562 facebook/prop-types#194 for some background information. However, it seems that at the time mui-places-autocomplete was last published, fbjs was still used via prop-types and simply not listed in the package.json. If you could publish a new version with the latest prop-types package to remove the fbjs dependency entirely, that would be great.

Material UI V1 is out - breaking changes

Hey @Giners

It's just come to my attention that Material-UI Version 1 is finally out, and there are some breaking changes

Consequently I'm getting a compilation error, in my app that's now using MUI V1:
Module not found: Can't resolve 'material-ui/Menu' in '/..../node_modules/mui-places-autocomplete/dist

so instead of: import { MenuList, MenuItem } from 'material-ui/Menu'
you need: import { MenuList, MenuItem } from '@material-ui/core/Menu'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.