Google Maps Places lat/lng not populating in Form

79 Views Asked by At

I have a Ruby on Rails 7 app and I am using Google Maps Places Autocomplete API to fill in a form with bar name, address, website, etc. This code works fine and has been for awhile.

I am trying to add lat/lng to the form so I can save them to the database and use them to display markers on a map elsewhere in my site. The issue I am having is the lat/lng is not populating in my form. I have created text_fields so I can visually see if the lat/lng is populating (in production these will be hidden fields).

I can see in the console response the Google Places is pulling the lat/lng but for some reason I cannot get it to populate in my form.

Here is my /app/javascript/controllers/places_controller.js file:

import { Controller } from "@hotwired/stimulus";

// console.log("google places controller loaded")


export default class extends Controller {
  static targets = [ "field" ]

  connect() {
    if (typeof(google) != "undefined") {
    this.initPlaces()
    }
  }

  initPlaces() {

    this.autocomplete = new google.maps.places.Autocomplete(this.fieldTarget)
    this.autocomplete.setFields(['address_components', 'geometry', 'website', 'name'])
    this.autocomplete.addListener('place_changed', this.fillInAddress.bind(this))

  }

  placeChanged() {
    let place = this.autocomplete.getPlace()

    if (!place.geometry) {
      window.alert(`No details available for input: ${place.name}`)
      return
    }
  }

  keydown(event) {
    if (event.key == "Enter") {
      event.preventDefault()
    }
  }


  fillInAddress() {
    // Get the place details from the autocomplete object.
    const place = this.autocomplete.getPlace();
    console.log("Place selected:", place); // Debugging line

    if (place.geometry && place.geometry.location) {
      // Accessing the latitude and longitude
      const lat = place.geometry.location.lat();
      const lng = place.geometry.location.lng();

      console.log("Latitude before setting field:", lat); // Debugging
      console.log("Longitude before setting field:", lng); // Debugging

      // Set the latitude and longitude in the form fields
      document.querySelector("#bar_info_latitude").value = lat;
      document.querySelector("#bar_info_longitude").value = lng;

      console.log("Latitude after setting field:", document.querySelector("#bar_info_latitude").value); // Debugging
      console.log("Longitude after setting field:", document.querySelector("#bar_info_longitude").value); // Debugging
    } else {
      console.log("Selected place does not have geometry or location");
    }

    let bar_info_addressline1 = "";

    document.querySelector("#bar_info_barname").value = place.name
    document.querySelector("#bar_info_website").value = place.website

    // Get each component of the address from the place details,
    // and then fill-in the corresponding field on the form.
    // place.address_components are google.maps.GeocoderAddressComponent objects
    // which are documented at http://goo.gle/3l5i5Mr
    for (const component of place.address_components) {
      const componentType = component.types[0];

      switch (componentType) {
        case "street_number": {
          bar_info_addressline1 = `${component.long_name} ${bar_info_addressline1}`;
          break;
        }

        case "route": {
          bar_info_addressline1 += component.short_name;
          break;
        }

        case "postal_code": {
          document.querySelector("#bar_info_zip").value = component.long_name;
          break;
        }
        case "locality":
          document.querySelector("#bar_info_city").value = component.long_name;
          break;

        case "administrative_area_level_1": {
          document.querySelector("#bar_info_state").value = component.short_name;
          break;
        }
      }
    }
    // bar_info_addressline1Field.value = bar_info_addressline1;
    document.querySelector("#bar_info_addressline1").value = bar_info_addressline1;

    // After filling the form with address components from the Autocomplete
    // prediction, set cursor focus on the second address line to encourage
    // entry of subpremise information such as apartment, unit, or floor number.
    document.querySelector("#bar_info_addressline2").focus();
  }

}

Here is my _form.html.erb partial code:

<div class="row">
    <div class="col-md 6">
        <%= form_with(model: @bar_info, local: true, data: { controller: "places" }) do |f| %>
        <%= render 'shared/error_messages', object: f.object %>

        <%= f.label "Bar Name (required)" %>
        <%= f.text_field :barname, placeholder: "Bar name here", class: "form-control", size: "70x1", data: { places_target: "field", action: "keydown->places#keydown" } %>

        <% if is_an_admin? || cmdr_user? %>
        <!-- Only admin and cmdr_user gets to use autocomplete feature, to save on google cloud costs -->

        <div class="form-group">
        <%= f.label :address %>
        <%= f.text_field :addressline1, class: 'form-control' %>


        <%= f.label "Address Line 2" %>
        <%= f.text_field :addressline2, placeholder: "Street Address 2", class: "form-control", size: "70x1" %>
        <% end %>

        <%= f.label "City (required)" %>
        <%= f.text_field :city, placeholder: "City", class: "form-control", size: "70x1" %>


        <%= f.label "State (required)" %>
        <%= f.text_field :state, placeholder: "State", class: "form-control" %>

        <% if is_an_admin? || cmdr_user? %>
        <%= f.label :zip %>
        <%= f.text_field :zip, placeholder: "Postal Code", class: "form-control", size: "70x1" %>
        <% end %>

        <p class="mt-2">Not required, but would love to have the information below too!</p>

        <%= f.label :website %>
        <%= f.url_field :website, placeholder: "https://www.example.com", class: "form-control" %>

        <%= f.label :instagram %>
        <div class="input-group mb-3">
            <span class="input-group-text" id="basic-addon1">@</span>
            <%= f.text_field :instagram, placeholder: "username", class: "form-control" %>
        </div>
        <br>

        <%= f.text_field :latitude %>
        <%= f.text_field :longitude %>

        </div>

        <% if is_an_admin? || cmdr_user? %>
        <span class="image">
            <p>Upload an image of Bar here!</p>
            <%= f.file_field :image, accept: "image/jpeg,image/gif,image/png",
                data: { controller: "image-upload", image_upload_target: "image", action: "change->image-upload#checkSize" },
                class: "form-control mb-3", id: "formFile" %>
        </span>
        <% end %>

        <%= f.submit "Submit", class: "btn btn-primary" %>
        <% end %>
    </div>
</div>

HTML output of the lat/lng text_field in the form:

<input type="text" name="bar_info[latitude]" id="bar_info_latitude">
<input type="text" name="bar_info[longitude]" id="bar_info_longitude">

The Places API console response with the lat/lng. All other address components correctly autofill the form


77
      "geometry" : 
78
      {
79
         "location" : 
80
         {
81
            "lat" : 34.0532482,
82
            "lng" : -118.2505517
83
         },
0

There are 0 best solutions below