Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mrosenblatt's avatar

Places Autocomplete

Hey there,

I've got a page that requires Google Places Autocomplete. This can cause issues where when a textbox is auto-filled by the autocomplete script, the changes aren't detected by Livewire.

I did some digging, and I basically found that the following should work --

    address1Field.dispatchEvent(new Event('input'));
    address2Field.dispatchEvent(new Event('input'));
    serviceCity.dispatchEvent(new Event('input'));

However, whenever dispatchEvent is run, it seems like the Google Autocomplete script doesn't finish execution so the popup showing the autocomplete dropdown gets permanently stuck on the screen and the autocomplete drop down doesn't seem to reset itself.

Does anyone know of a better / cleaner way of handling this? Is there an event in Google Places Autocomplete I should listen for to trigger my updates that executes after it's finished doing what it needs to do? I can't seem to find one if it exists.

Below is the entire script I've got, which is a slightly modified version of what Google has published


let autocomplete;
let address1Field;
let address2Field;
let postalField;
let serviceCity;
let serviceState;
let serviceCounty;
let serviceCountry;

function initAutocomplete() {
  address1Field = document.querySelector("#service_address");
  address2Field = document.querySelector("#service_suite");
  postalField = document.querySelector("#service_zip");
  serviceCity = document.querySelector("#service_city");
  serviceState = document.querySelector("#service_state");
  serviceCounty = document.querySelector("#service_county");
  serviceCountry = document.querySelector("#service_country");

  autocomplete = new google.maps.places.Autocomplete(address1Field, {
    componentRestrictions: { country: ["us", "ca"] },
    fields: ["address_components", "geometry"],
    types: ["address"],
  });
  address1Field.focus();

  autocomplete.addListener("place_changed", fillInAddress);
  autocomplete.addListener("place_changed", updateLivewire);

}

function fillInAddress() {

  const place = autocomplete.getPlace();
  let address1 = "";
  let postcode = "";


  for (const component of place.address_components) {

    const componentType = component.types[0];

    switch (componentType) {
        case "street_number": {
            address1 = `${component.long_name} ${address1}`;
            break;
        }
        case "route": {
            address1 += component.short_name;
            break;
        }
        case "postal_code": {
            postcode = `${component.long_name}${postcode}`;
            break;
        }
        case "postal_code_suffix": {
            postcode = `${postcode}-${component.long_name}`;
            break;
        }
        case "locality":
            serviceCity.value = component.long_name;
            break;
        case "administrative_area_level_1": {
            serviceState.value = component.short_name;
            break;
        }
        case "administrative_area_level_2":
            serviceCounty.value = component.long_name;
            break;
        case "country":
            serviceCountry.value = component.long_name;
            break;
    }
  }

  address1Field.value = address1;
  postalField.value = postcode;
  
  address2Field.focus();
  
}

function updateLivewire(){

    address1Field.dispatchEvent(new Event('input'));
    address2Field.dispatchEvent(new Event('input'));
    serviceCity.dispatchEvent(new Event('input'));
    serviceState.dispatchEvent(new Event('input'));
    postalField.dispatchEvent(new Event('input'));
    serviceCounty.dispatchEvent(new Event('input'));
    serviceCountry.dispatchEvent(new Event('input'));

}

window.initAutocomplete = initAutocomplete;
0 likes
2 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

To handle the Google Places Autocomplete with Livewire, you need to ensure that the Livewire component is aware of the changes made by the Google Places Autocomplete script. The issue you're facing is likely due to the timing of the events and how they are dispatched.

Here's a refined approach to ensure that the Livewire component detects the changes correctly:

  1. Debounce the input events: This will help in ensuring that the events are not fired too quickly, which might be causing the autocomplete dropdown to get stuck.

  2. Use a custom event: Instead of directly dispatching the 'input' event, you can create a custom event that Livewire can listen to.

Here's the updated script:

let autocomplete;
let address1Field;
let address2Field;
let postalField;
let serviceCity;
let serviceState;
let serviceCounty;
let serviceCountry;

function initAutocomplete() {
  address1Field = document.querySelector("#service_address");
  address2Field = document.querySelector("#service_suite");
  postalField = document.querySelector("#service_zip");
  serviceCity = document.querySelector("#service_city");
  serviceState = document.querySelector("#service_state");
  serviceCounty = document.querySelector("#service_county");
  serviceCountry = document.querySelector("#service_country");

  autocomplete = new google.maps.places.Autocomplete(address1Field, {
    componentRestrictions: { country: ["us", "ca"] },
    fields: ["address_components", "geometry"],
    types: ["address"],
  });
  address1Field.focus();

  autocomplete.addListener("place_changed", fillInAddress);
}

function fillInAddress() {
  const place = autocomplete.getPlace();
  let address1 = "";
  let postcode = "";

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

    switch (componentType) {
      case "street_number": {
        address1 = `${component.long_name} ${address1}`;
        break;
      }
      case "route": {
        address1 += component.short_name;
        break;
      }
      case "postal_code": {
        postcode = `${component.long_name}${postcode}`;
        break;
      }
      case "postal_code_suffix": {
        postcode = `${postcode}-${component.long_name}`;
        break;
      }
      case "locality":
        serviceCity.value = component.long_name;
        break;
      case "administrative_area_level_1": {
        serviceState.value = component.short_name;
        break;
      }
      case "administrative_area_level_2":
        serviceCounty.value = component.long_name;
        break;
      case "country":
        serviceCountry.value = component.long_name;
        break;
    }
  }

  address1Field.value = address1;
  postalField.value = postcode;

  // Dispatch custom event to notify Livewire
  dispatchLivewireEvent();
}

function dispatchLivewireEvent() {
  const event = new CustomEvent('google-autocomplete', {
    detail: {
      address1: address1Field.value,
      address2: address2Field.value,
      city: serviceCity.value,
      state: serviceState.value,
      postal: postalField.value,
      county: serviceCounty.value,
      country: serviceCountry.value,
    }
  });

  document.dispatchEvent(event);
}

window.initAutocomplete = initAutocomplete;

In your Livewire component, you can listen for this custom event and update the properties accordingly:

<script>
    document.addEventListener('google-autocomplete', function (event) {
        @this.set('address1', event.detail.address1);
        @this.set('address2', event.detail.address2);
        @this.set('city', event.detail.city);
        @this.set('state', event.detail.state);
        @this.set('postal', event.detail.postal);
        @this.set('county', event.detail.county);
        @this.set('country', event.detail.country);
    });
</script>

This approach ensures that the Livewire component is updated with the values from the Google Places Autocomplete script without causing the autocomplete dropdown to get stuck.

1 like
mrosenblatt's avatar

This is mostly working, but there's one thing that's still not that's throwing me for a total loop --

<script>
    document.addEventListener('google-autocomplete', function (event) {
        @this.set('form.service_address', event.detail.service_address);
        @this.set('form.service_suite', event.detail.service_suite);
        @this.set('form.service_city', event.detail.service_city);
        @this.set('form.service_state', event.detail.service_state);
        @this.set('form.service_zip', event.detail.service_zip);
        @this.set('form.service_county', event.detail.service_county);
        @this.set('form.service_country', event.detail.service_country);
        console.log(event.detail.service_address)
    });
</script>

This will successfully write the address to the console, but $form->service_address doesn't end up updating. I have a field that spits out the values of everything relevant in $form, as seen below

<div class="card-body">
                        Address: {{ $form->service_address }}<br>
                        Suite: {{ $form->service_suite }}<br>
                        City: {{ $form->service_city }}<br>
                        State: {{ $form->service_state }}<br>
                        Zip: {{ $form->service_zip }}<br>
                        County: {{ $form->service_county }}<br>
                        Country: {{ $form->service_country }}<br>
                    </div>

Everything updates and displays appropriately, except for $form->service_address.

Please or to participate in this conversation.