rails 5 turbolinks 5 and google maps how to?
Asked Answered
A

4

7

I'm using rails 5 with turbolinks 5 and trying to get google places autocomplete address form to work using the example from google's website found here

I only want to load the javascript and google maps library on this page.

What would be the correct way to get the following javascript to work with rails 5 and turbolinks 5.

<script>
  // This example displays an address form, using the autocomplete feature
  // of the Google Places API to help users fill in the information.

  // This example requires the Places library. Include the libraries=places
  // parameter when you first load the API. For example:
  // <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">

  var placeSearch, autocomplete;
  var componentForm = {
    street_number: 'short_name',
    route: 'long_name',
    locality: 'long_name',
    administrative_area_level_1: 'short_name',
    country: 'long_name',
    postal_code: 'short_name'
  };

  function initAutocomplete() {
    // Create the autocomplete object, restricting the search to geographical
    // location types.
    autocomplete = new google.maps.places.Autocomplete(
        /** @type {!HTMLInputElement} */(document.getElementById('autocomplete')),
        {types: ['geocode']});

    // When the user selects an address from the dropdown, populate the address
    // fields in the form.
    autocomplete.addListener('place_changed', fillInAddress);
  }

  function fillInAddress() {
    // Get the place details from the autocomplete object.
    var place = autocomplete.getPlace();

    for (var component in componentForm) {
      document.getElementById(component).value = '';
      document.getElementById(component).disabled = false;
    }

    // Get each component of the address from the place details
    // and fill the corresponding field on the form.
    for (var i = 0; i < place.address_components.length; i++) {
      var addressType = place.address_components[i].types[0];
      if (componentForm[addressType]) {
        var val = place.address_components[i][componentForm[addressType]];
        document.getElementById(addressType).value = val;
      }
    }
  }

  // Bias the autocomplete object to the user's geographical location,
  // as supplied by the browser's 'navigator.geolocation' object.
  function geolocate() {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(function(position) {
        var geolocation = {
          lat: position.coords.latitude,
          lng: position.coords.longitude
        };
        var circle = new google.maps.Circle({
          center: geolocation,
          radius: position.coords.accuracy
        });
        autocomplete.setBounds(circle.getBounds());
      });
    }
  }
</script>

<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initAutocomplete"
    async defer></script>
Assagai answered 14/8, 2016 at 10:23 Comment(0)
A
-3

As per the documentation:

Turbolinks evaluates script elements in a page’s body each time it renders the page. You can use inline body scripts to set up per-page JavaScript state or bootstrap client-side models. To install behavior, or to perform more complex operations when the page changes, avoid script elements and use the turbolinks:load event instead.

But the reason it wasn't working for me was because in layouts/application.html.erb I had:

<%= javascript_include_tag "application", 'data-turbolinks-track' => true %>

when it should be:

<%= javascript_include_tag "application", 'data-turbolinks-track': 'reload' %>
Assagai answered 15/8, 2016 at 7:35 Comment(1)
This is not the correct answer, this also changes the turbolinks behavior in a way which is not benificial.Heresiarch
B
6

I solved Turbolinks 5 and Google Maps API problem just with data-turbolinks-eval="false" attribute on my google maps script tag.

... application.html.erb
<head>
<!-- Other HTML page Head content -->    
<title><%= content_for?(:title) ? yield(:title) : "Untitled" %></title>
<script async src="https://maps.googleapis.com/maps/api/js?key=YOUR_GOOGLE_MAPS_API_KEY" data-turbolinks-eval="false"></script>
<%= javascript_include_tag "application", 'data-turbolinks-track' => 'reload' %>
</head>

and in your coffee/js files use:

coffee:
$(document).on "turbolinks:load", ->
  map = new google.maps.Map $('map').get(0), mapOptions
js:
$(document).on("turbolinks:load", function(){
  map = new google.maps.Map($('map').get(0), mapOptions)
})
Beamon answered 16/3, 2017 at 18:51 Comment(2)
This will not work because the JS needs to be unloaded and removed when the page unload event happens, otherwise the JS for this component will not work on subsequent pages.Heresiarch
Google script would be evaluated by browser, not by turbolinks. So it'd be reloaded in each page. And when turbolinks are ready we can create google maps object.Scully
J
3

Try this too....

google.maps.event.addDomListener(window, 'turbolinks:load', initialize);
Janice answered 15/9, 2016 at 3:43 Comment(1)
Great solution. Thanks. See also: github.com/turbolinks/turbolinks/blob/master/src/turbolinks/…Shudder
G
0

I was not happy with other answers as Google Maps throws a warning if loaded multiple times, e.g. while re-visiting a page, and disabling Turbolinks defeats its purpose. Also using Google Maps JavaScript API's callback argument forces you to pollute window name space.

Instead we can get Google Maps scripts, e.g. with jQuery, if and only if it is not loaded yet. Here is the CoffeeScript that I use with Rails 4.2.10:

initMap = ->
  ...
$(document).on 'turbolinks:load', ->
//  if you would like to limit what views are affected
//  see https://brandonhilkert.com/blog/organizing-javascript-in-rails-application-with-turbolinks/
//  return unless $('.plots.map').length > 0
  if typeof(google)=='undefined' or typeof(google.maps)=='undefined'
    $.get
      url: "https://maps.googleapis.com/maps/api/js?key=<use_your_key>&libraries=geometry"
      dataType: 'script'
      success: initMap
  else
    initMap()
Gravimetric answered 27/9, 2018 at 23:27 Comment(0)
A
-3

As per the documentation:

Turbolinks evaluates script elements in a page’s body each time it renders the page. You can use inline body scripts to set up per-page JavaScript state or bootstrap client-side models. To install behavior, or to perform more complex operations when the page changes, avoid script elements and use the turbolinks:load event instead.

But the reason it wasn't working for me was because in layouts/application.html.erb I had:

<%= javascript_include_tag "application", 'data-turbolinks-track' => true %>

when it should be:

<%= javascript_include_tag "application", 'data-turbolinks-track': 'reload' %>
Assagai answered 15/8, 2016 at 7:35 Comment(1)
This is not the correct answer, this also changes the turbolinks behavior in a way which is not benificial.Heresiarch

© 2022 - 2024 — McMap. All rights reserved.