Vue Autosuggest Autocomplete Select From Multiple Source

Data Source from REST Api and Google Places

I want to build an autocomplete select/dropdown using vue-autosuggest from 2 sources: Google Places and REST API.

vue-autosuggest is not the most popular ones, but it is actively developed for the last 12 months. I am using version 1.4.3 (18 Jul 2018).

Install

Install vue-autosuggest (for autocomplete dropdown) and axios (for calling REST Api)

npm install --save vue-autosuggestnpm install --save axios

PlacePicker Component

I created a vue component: PlacePicker.vue.

NOTE: Take note of Places API Policies

<template>  <form>    <vue-autosuggest        :suggestions="suggestions"        :inputProps="inputProps"        :sectionConfigs="sectionConfigs"        :renderSuggestion="renderSuggestion"        :getSuggestionValue="getSuggestionValue"        ref="autocomplete" />    <div id="map" style="height: 300px;"></div>  </form></template>  <script>import Vue from 'vue'import axios from 'axios'let googleMapPromise = nulllet map = nulllet placeService = nulllet autocompleteService = nulllet timeout = nulllet marker = nullexport default {  name: 'PlacePicker',  props: ['query'],  data() {    GOOGLE_API_KEY: '<PUT_YOUR_KEY>',    selected: '',    suggestions: [],    sectionConfigs: {      googleSuggest: {        limit: 6,        label: 'Suggestions',        onSelected: selected => {          this.fetchResults(selected.item, "")          // https://github.com/Educents/vue-autosuggest/issues/52          this.$refs.autocomplete.listeners.click()        }      },      travelopy: {        limit: 6,        label: 'Travelopy',        onSelected: selected => {          this.selected = selected        }      },      google: {        limit: 6,        label: 'Google',        onSelected: selected => {          this.selected = selected        }      }    },    inputProps: {      id: "autosuggest__input",      onInputChange: this.fetchResults,      placeholder: 'Search places',      initialValue: this.query,    }  },  watch: {    selected(value) {      if (value) {        const item = value.item        if (item.location) {          if (!marker) {            marker = new google.maps.Marker({ position: item.location, map: map, title: item.name })          }          else {            marker.setPosition(item.location)            marker.setTitle(item.name)          }          map.panTo(item.location)        }        else {          this.$toasted.show('Selection had no location')        }      }    },    fetchResults(val) {      this.selected = null      let delay = 300      const len = val.length      if (len == 0) {        this.suggestions = []        return      }      else if (len == 1) {        delay = 1000      }      else if (len <= 3) {        delay = 700      }      else if (len <= 5) {        delay = 500      }      clearTimeout(timeout)      timeout = setTimeout(() => {        // hack to maintain position        this.suggestions = [          {name: 'google', data: null},          {name: 'travelopy', data: null},          {name: 'googleSuggest', data: null},          ]        axios.get(`/your_autocomplete_rest_api?q=${val}`)          .then(response => {              const results = response.data              if (results.length === 0) return              const newResults = results.map(item => {                // TODO: perform your own mapping here                let name = item.name                const alt_names = []                if (item.native_name)                  name += ` (${item.native_name})`                let location = null                if (item.geo) {                  const latlng = item.geo.split(', ')                  location = new google.maps.LatLng(latlng[0], latlng[1])                }                return {                  id: item.id,                  type: 'place',                  name: name,                  address: item.address,                  location: location,                  place_type: item._item_type,                }              })              const suggestion = { name: 'travelopy', data: newResults }              const index = this.suggestions.findIndex(x => x.name === 'travelopy')              if (index === -1)                this.suggestions.push(suggestion)              else                Vue.set(this.suggestions, index, suggestion)          })          .catch((error) => {              // const message = lua.util.getErrorMessage(error)              // this.$toasted.error(message)          })        const request = {          query: val,          fields: ['place_id', 'name', 'formatted_address', 'icon', 'geometry'],          // locationBias: null,        }        placeService.findPlaceFromQuery(request, (results, status) => {        // placeService.textSearch(request, (results, status) => {          if (status == google.maps.places.PlacesServiceStatus.OK) {            // raw is used by new_api.py for new place creation            const newResults = results.map(item => ({ id: item.place_id, type: 'google_place', name: item.name, address: item.formatted_address, location: item.geometry.location, place_icon: item.icon, raw: item }))            const suggestion = { name: 'google', data: newResults }            const index = this.suggestions.findIndex(x => x.name === 'google')            if (index === -1)              this.suggestions.push(suggestion)            else              Vue.set(this.suggestions, index, suggestion)          }        })        const autocompleteRequest = {          input: val,        }        autocompleteService.getPlacePredictions(autocompleteRequest, (results, status) => {          if (status == google.maps.places.PlacesServiceStatus.OK) {            const newResults = results.map(item => (item.description))            const suggestion = { name: 'googleSuggest', data: newResults }            const index = this.suggestions.findIndex(x => x.name === 'googleSuggest')            if (index === -1)              this.suggestions.push(suggestion)            else              Vue.set(this.suggestions, index, suggestion)          }        })      }, delay)    },    renderSuggestion(suggestion) {      const item = suggestion.item      if (suggestion.name === 'travelopy') {        return (          <div>            <div class="float-right text-secondary">{item.place_type}</div>            <div>{item.name}</div>            <small class="text-secondary">{item.address}</small>          </div>        )      } else if (suggestion.name === 'google') {        return (          <div>            <img class="float-right" style="max-width: 18px;" src={item.place_icon} />            <div>{item.name}</div>            <small class="text-secondary">{item.address}</small>          </div>        )      } else {        // assume this is string        return item      }    },    getSuggestionValue(item) {      if (item.name == "travelopy" || item.name == "google") {        return item.item.name      } else {        return item.item      }    },  },  created() {    googleMapPromise = loadScript('https://maps.googleapis.com/maps/api/js?key=' + this.GOOGLE_API_KEY + '&libraries=places')  },  mounted() {    googleMapPromise.then(() => {      var mapCenter = new google.maps.LatLng(-33.8617374,151.2021291)      map = new google.maps.Map(document.getElementById('map'), {          center: mapCenter,          zoom: 15        })      marker = null      placeService = new google.maps.places.PlacesService(map)      autocompleteService = new google.maps.places.AutocompleteService()    })  }}</script>

References:

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.