Forgive me if I'm a bit confused, I'm venturing out into new terratory in my programming, and learning as I go. The basic concept I'm struggling with:
In my Rails 4 app I'm using Leaflet (a JS library for mapping) and calling some of my own code. Long story short, I was unable to get Leaflet and Turbolinks to play well together so for the pages in my site that need Leaflet I've disabled Turbolinks, additionally I'm loading page specific Coffeescript.
I've now decided that I want to add a back button. The usage would go like this - from a page that is using Leaflet, the user can click on a piece of the map and be taken to a page that uses Turbolinks (if it matters). From the Turbolinks page, I have a back button to take you back to the Leaflet map.
However, when I get back to the Leaflet page, my coffeescript either isn't being run, or is being run at the wrong time (I get several errors that weren't there the first time it ran). I'm guessing I would need to add another event at the beginning of the Coffeescript or choose a different event, but I'm just not sure what it should be.
I am in no way wedded to not using Turbolinks on the Leaflet page if you have a suggestion for how to make it work and it helps to get the back button to work. :)
_navbar.html.erb
<li><%= link_to("By grid", grid_path, data: {turbolinks: false}) %></li>
grid.html.erb
... code for layout goes here ...
<% content_for :header do %>
<%= javascript_include_tag "leaflet" %>
<% end %>
<% content_for :javascript do %>
<%= javascript_include_tag "leaflet-maps/#{filename}" %>
<% end %>
leaflet-maps/grid.coffee
$ ->
document.addEventListener 'page:restore', ->
app.init()
return
... rest of coffeescript goes here ...
... here is how the link is getting called
layer.on 'click', (e) ->
window.location.href='/show?grid='+feature.id
return
show.html.erb
<%= link_to "Back", :back %>
Update
grid.coffee
- full coffeescript code
ready = ->
#--------------------------------------------------
# Build tooltip with plant name
#--------------------------------------------------
onEachFeature = (feature, layer) ->
if feature.properties and feature.properties.grid_name
layer.bindTooltip feature.properties.grid_name
layer.on 'click', (e) ->
window.location.href='/show?grid='+feature.id
return
return
#--------------------------------------------------
# Variables
#--------------------------------------------------
L.Icon.Default.imagePath = '/assets'
gridStyle = {
"color": "#ff7800",
}
neCorner = L.latLng([47.635103, -122.320525])
swCorner = L.latLng([47.634083, -122.321129])
#--------------------------------------------------
# Set view and load Google Maps
#--------------------------------------------------
map = L.map("map", zoomSnap: .25)
map.fitBounds([swCorner, neCorner])
map.invalidateSize(false)
map.options.maxZoom = 22
map.options.bounceAtZoomLimits = true
googleLayer = L.gridLayer.googleMutant(type: 'roadmap').addTo(map)
map.addLayer googleLayer
#--------------------------------------------------
# Get Ajax data
#--------------------------------------------------
$.ajax
dataType: 'text'
url: 'grid.json'
success: (data) ->
L.geoJSON(JSON.parse(data), style: gridStyle, onEachFeature: onEachFeature ).addTo map
error: ->
alert "Failed to load AJAX data"
document.addEventListener 'turbolinks:load', ready()
document.addEventListener 'DOMContentLoaded', ready()
So, there are two places where you might be going off-track. The first is here:
What this is saying is... "when the web page emits the DOMContentLoaded event, then, when something else emits the
page:restore
event, then, run my JavaScript code."Let's start with
DOMContentLoaded
. This is an event browsers emit by default, and which the jQuery framework uses to trigger event listeners. You can read more about jQuery's.ready()
function here.The
page:restore
event is NOT a standardly-emitted event, but was a custom event used in Turbolinks Classic (version <5.0, deprecated as of February 2016), which I believe you're using since you mentioned Rails 4.Either way, stacking both listeners on top of one another is probably not what you want to do. What you could do it define a function to run on both
ready
andpage:restore
...(Sorry, I realize you're writing CoffeeScript. That's not my jam. I hope my JavaScript is OK...)
That's one. I see another opportunity for improvement.
What you're saying is "when the document is loaded, listen for clicks on the
layer
object, and then do this thing."I'm not exactly sure what
layer
is, and if it's Leaflet-specific I probably won't be able to help you. However, there's actually a more resilient way to write this.This might seem identical, but there's a subtle difference. It's saying "any time I click on the document, if I also happen to be clicking on a layer, do this thing."
This is more resilient because your line of JavaScript can always find the
document
when it's run. If yourlayer
hasn't rendered by the time that line of code runs, it'll never catch those clicks.Happy JavaScripting! :)