Search code examples
javascriptvue.jsvuetify.jsgoogle-places-apigoogle-places-autocomplete

Input gets disabled when Google Places API Autocomplete fails authorization


When using Google Places API Autocomplete with Vue/Vuetify, if the API script fails to authorize, the text field becomes disabled and further input is disallowed after the first character.

How can I make it so that it fails quietly in the background and allows text to be entered?

I understand that there's gm_authFailure() and that the Places API will call it globally in the event of a failure, but I'm not sure how to allow the function to call it in Vue.

JSFiddle: https://jsfiddle.net/wya72b0j/

HTML:

<div id="app">
  <v-app>
    <v-container class="ma-auto pa-auto blue-grey darken-4 fill-height">
      <v-row justify="center" class="mx-5 px-5">
        <v-text-field
          v-model="billingAddress"
          @focus="billingAutocomplete()"
          required
          ref="billautocomplete">
          </v-text-field>
      </v-row>
    </v-container>
  </v-app>
</div>

Vue:

new Vue({
  el: "#app",
  vuetify: new Vuetify({
    theme: {
      dark: true,
    }
  }),
  data: () => ({
    billingAddress: '',
  }),
  mounted() {
    const placesapi = document.createElement('script')
    placesapi.setAttribute(
      'src',
      'https://maps.googleapis.com/maps/api/js?key=ThisKeyNotDoesNotWork&libraries=places'
    )
    document.head.appendChild(placesapi)
  },
  methods: {
    billingAutocomplete() {
      let addressArray = {
        street_number: '',
        route: '',
        locality: '',
        administrative_area_level_1: '',
        country: '',
        postal_code: '',
      }

      let element = this.$refs.billautocomplete.$refs.input
      const google = window.google

      let autocomplete = new google.maps.places.Autocomplete(element, {
        types: ['geocode'],
        componentRestrictions: {
          country: 'us'
        },
      })

      autocomplete.setFields(['address_component'])

      autocomplete.addListener('place_changed', () => {
        const componentForm = {
          street_number: 'short_name',
          route: 'long_name',
          locality: 'long_name',
          administrative_area_level_1: 'short_name',
          country: 'long_name',
          postal_code: 'short_name',
        }

        let place = autocomplete.getPlace()

        for (const component of place.address_components) {
          const addressType = component.types[0]

          if (componentForm[addressType]) {
            const val = component[componentForm[addressType]]
            addressArray[addressType] = val
          }
        }

        this.billingAddress = addressArray
      })
    }
  }
})

Solution

  • I got it to work, but it's a bit hacky. First I added an id tag to the v-text-field to prevent disabled and empty placeholder. Under the <script> tag I added window.gm_authFailure() in an essentially empty function and finally under mounted, I added the real function that handled the input from being disabled. I'm sure there's a better/proper way, but this works.

    updated JSFiddle: https://jsfiddle.net/90ua3xzy/

    HTML:

    <v-text-field
      v-model="billingAddress"
      @focus="billingAutocomplete()"
      required
      ref="billautocomplete"
      id="billingautocomplete">
    </v-text-field>
    

    Vue:

    <script>
    window.gm_authFailure = function() {
      return false
    }
    [...]
    mounted() {
      window.gm_authFailure = function() {
        document.getElementById('billingautocomplete').disabled = false
        document.getElementById('billingautocomplete').placeholder = ''
      }
    [...]