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
},