/ Gists / 7 Google maps autocomplete
On gists

7 Google maps autocomplete

cdruc vue

index.html Raw #

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Tallpad</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_GOOGLE_API_KEY&libraries=places"></script>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

AddressFieldGroup.vue Raw #

// https://tallpad.com/series/vuejs-misc/lessons/google-maps-autocomplete-with-vuejs

<template>
  <h3 class="text-lg font-medium">{{ label }}</h3>
  <div class="grid grid-cols-3 gap-5">
    <label class="col-span-2 block text-sm font-medium text-gray-700">
      Street
      <input
        class="block mt-1 w-full text-sm placeholder-gray-400 rounded-md border-gray-300 focus:ring-blue-500 focus:border-blue-500"
        type="text"
        @input="$emit('update:street', $event.target.value)"
        :value="street"
        ref="streetRef"
        placeholder="Street"/>
    </label>

    <label class="block text-sm font-medium text-gray-700">
      Number
      <input
        class="block mt-1 w-full text-sm placeholder-gray-400 rounded-md border-gray-300 focus:ring-blue-500 focus:border-blue-500"
        type="text"
        @input="$emit('update:streetNumber', $event.target.value)"
        :value="streetNumber"
        placeholder="Number"/>
    </label>

    <label class="block text-sm font-medium text-gray-700">
      Postcode
      <input
        class="block mt-1 w-full text-sm placeholder-gray-400 rounded-md border-gray-300 focus:ring-blue-500 focus:border-blue-500"
        type="text"
        @input="$emit('update:postcode', $event.target.value)"
        :value="postcode"
        placeholder="Postcode"/>
    </label>

    <label class="block text-sm font-medium text-gray-700">
      City
      <input
        class="block mt-1 w-full text-sm placeholder-gray-400 rounded-md border-gray-300 focus:ring-blue-500 focus:border-blue-500"
        type="text"
        @input="$emit('update:city', $event.target.value)"
        :value="city"
        placeholder="City"/>
    </label>

    <label class="block text-sm font-medium text-gray-700">
      Country
      <input
        class="block mt-1 w-full text-sm placeholder-gray-400 rounded-md border-gray-300 focus:ring-blue-500 focus:border-blue-500"
        type="text"
        @input="$emit('update:country', $event.target.value)"
        :value="country"
        placeholder="Country"/>
    </label>
  </div>
</template>

<script>
import {onMounted, onUnmounted, ref} from "vue";

export default {
  props: {
    label: {
      type: String,
      default: '',
    },
    street: {
      type: String,
      default: '',
    },
    streetNumber: {
      type: String,
      default: '',
    },
    postcode: {
      type: String,
      default: '',
    },
    city: {
      type: String,
      default: '',
    },
    country: {
      type: String,
      default: '',
    },
  },
  setup(props, context) {
    const streetRef = ref();
    let autocomplete;

    onMounted(() => {
      autocomplete = new google.maps.places.Autocomplete(streetRef.value, {
        types: ["address"],
        fields: ["address_components"]
      });

      google.maps.event.addListener(autocomplete, "place_changed", () => {
        const mapping = {
          street_number: "update:streetNumber",
          route: "update:street",
          locality: "update:city",
          postal_code: "update:postcode",
          country: "update:country",
        }

        for(const type in mapping) {
          context.emit(mapping[type], "");
        }

        let place = {
          address_components: [],
          ...autocomplete.getPlace()
        }

        place.address_components.forEach((component) => {
          component.types.forEach((type) => {
              if(mapping.hasOwnProperty(type)){
                context.emit(mapping[type], component.long_name);
              }
          });
        });
      });
    });

    onUnmounted(() => {
      if(autocomplete) {
        google.maps.event.clearInstanceListeners(autocomplete);
      }
    });

    return {streetRef};
  }
};
</script>