How do I add a conditional snippet of page specific javascript (likely a turbolinks issue)?
Here's to hoping I can be clear and concise about my problem. I am willing to venmo/paypal a beer's worth of cash to anyone who can help me π»
I currently have a bootstrap (3.3.7) modal that is, by default, inactive on the index page of a controller. It's just sitting there, waiting to pop up when I click a link.
In a scenario, I want that modal to automatically pop up (no link clicking required) when aformentioned index action is navigated to and a set of conditions are met.
On the index action of a controller (let's call it the "LearnController" for filename's sake), I perform a little bit of logic that compares cookie and database data to determine whether an instance variable holds a value of true
or false
in the index.html.erb
view and conditionally runs some javascript to force open the modal.
# app/controllers/learn.rb
class LearnController < ApplicationController
def index
...
@show_modal = do_logic
end
private
def do_logic
# ... looks at cookies and database to
# do some logic and return true or false...
end
end
# app/views/learn/index.html.erb
<% if @show_modal %>
<script>
document.addEventListener("turbolinks:load", function() {
$('#emailModal').modal('show');
}
</script>
<% end %>
I am able to test out the do_logic
I had written. It successfully compares the database & cookie data in the ways I want, and returns a true
or false
at appropriate times. Domain logic is good.
My issue now lies somewhere between my javascript architecture and Turbolinks.
When the controller makes the @show_modal = true
, the modal shows up, I fill out the email form or dismiss it entirely. In either event, the cookie is updated to make sure the @show_modal
returns false
and won't return true
again until other conditions are met in the future.
But, when I navigate around the app and back to the learn#index
page, @show_modal
returns false
but the turbolinks:load
event still fires and displays the modal when no javascript on the page asked it to.
If I refresh the page in the browser it seems to reload the turbolinks cache and everything works as designed until the next time @show_modal
returns true
and the browser caches that turbolinks:load
behavior again and fires when it shouldn't.
Some interesting things I've found:
- Inspecting the page after the modal opens when it shouldn't, my
<script>
tags aren't present in the DOM. The Railslearn#index
doesn't render that text again, yet the behavior stays until the cache is reloaded via a refresh on the browser. - Not only does triggering a reload in the browser fix the issue, but adding
<meta name="turbolinks-visit-control" content="reload">
to that specific page also seems to ensure that my code behaves properly. I don't like this solution because this index page is visited more than any page on the app and having turbolinks disabled on the most visited page makes the user experience slow and strange where it shouldn't be.
Do you see an obvious answer to this problem, or maybe you've had a similar struggle but implemented this one-off javascript differently?
Thanks!
Try adding some JS to hide the modal on the turbolinks:before-cache
event so it doesn't ever get saved when open.
I like your thinking, unfortunately it doesn't work :(
My temporary solution is now:
<% if @show_modal %>
<% content_for :head do %>
<meta name="turbolinks-visit-control" content="reload">
<% end %>
<script>
document.addEventListener("turbolinks:load", function() {
$('#emailModal').modal('show');
}
</script>
<% end %>
Which isn't ideal as it make forces a full page reload upon navigating back to the page, but at least it doesn't reload every visit.
This would be slightly slower, but what if instead of opening the modal on page load, you make an AJAX request to retrieve the value of @show_modal, and then depending on the response, you open the modal?
That way you're not trying dealing with any cache related things at all.
That could work? I'll test it later and let you know.
I'm surprised that Basecamp could develop a frameworks like Rails and Turbolinks and not account for SJR.
I did try to pass an index.js.erb
file to do this work as well but it didn't render the modal properly... may be a problem with bootstrap dependencies?... I just don't know anymore π