Rails 5: how to use $(document).ready() with turbo-links
Asked Answered
B

9

95

Turbolinks prevents normal $(document).ready() events from firing on all page visits besides the initial load, as discussed here and here. None of the solutions in the linked answers work with Rails 5, though. How can I run code on each page visit like in prior versions?

Bookshelf answered 20/3, 2016 at 6:15 Comment(0)
B
183

Rather than listen to the ready event, you need to hook in to an event fired by Turbolinks for every page visit.

Unfortunately, Turbolinks 5 (which is the version that appears in Rails 5) has been re-written, and does not use the same event names as in previous versions of Turbolinks, causing the answers mentioned to fail. What works now is to listen to the turbolinks:load event like so:

$( document ).on('turbolinks:load', function() {
  console.log("It works on each visit!")
})
Bookshelf answered 20/3, 2016 at 6:15 Comment(11)
Yes. Explained here as well. guides.rubyonrails.org/…. Check 5.2 Page Change Events.Gates
turbolinks:load fires for me locally, but not on Heroku. I see my custom javascript code in my compiled js assets, but the event isn't firing.Andras
this not work well. I have a select2 and when change the page and back I have two select2 (duplicated)Aleuromancy
Yes that's true @Aleuromancy I have the same issue and I also have opened a issue at GitHub. Have you solved somehow?Recognizor
Despite what the Rail doc says, I'm using on('ready turbolinks:load') otherwise I have some problems on some pagesMonition
Hi Cyril, I am having the same problem, i.e. need to trigger on initial page load as well as turbolinks:load. I have asked a question about this on SO, #41421996. Do you have any more insight as to why this is so? Are you using jquery-turbolinks (I am). The only good thing is it makes sure your code is idempotent.Sulphurbottom
For me, $(document).on('turbolinks:load', ...) did not work; I had to use document.addEventListener('turbolinks:load', ... as described in the Turbolinks README.Newsy
@Newsy That worked but I'm using a jquery upload button and file field with a progress bar. It adds another progress bar every time the page loads.Lorrimor
and could be used as following: $(document).on 'ready, turbolinks:load', -> ?Feingold
@CyrilDuchon-Doris That only makes it fire twice, hence why it isn't mentioned in the doc. As github.com/turbolinks/turbolinks/#observing-navigation-events says, you should do it like this: $(document).ready(function() { $(document).on('turbolinks:load', function() {} ) })Bui
Is this different for rails 6?Lavoie
R
68

Native JS :

document.addEventListener("turbolinks:load", function() {
    console.log('It works on each visit!');
});
Rein answered 25/10, 2016 at 9:9 Comment(1)
turbo:load for TurboNobles
D
14

In rails 5 the easiest solution is to use:

$(document).on('ready turbolinks:load', function() {});

Instead of $(document).ready. Works like a charm.

Drake answered 21/12, 2018 at 16:23 Comment(5)
Don't add ready to the list, otherwise the function will be executed twice. As github.com/turbolinks/turbolinks/#observing-navigation-events said, you should do it like this: javascript $(document).ready(function() { $(document).on('turbolinks:load', function() {} ) }) Diaconicon
@XiaohuiZhang Are you sure that's gonna work???? Because if $(document).ready gets triggered, then at least in my own scenarios, I wouldn't need turbolinks:loadDrake
@XiaohuiZhang If your script has to work on a page with turbolinks and on a page without, that will not work on the page without, because it will need the turbolinks:load event to execute the codeCinematography
@escanxr It works both, you can try it out. because Turbolinks always trigger "turbolinks:load" event whenever a Turbolinks page or not.Diaconicon
@XiaohuiZhang I tried with Turbolinks 5, it didn't work. If turbolinks is disabled on the page, only ready event is triggered. If there's turbolinks, the code is called twiceCinematography
D
9

This is my solution, override jQuery.fn.ready, then $(document).ready works without any change:

jQuery.fn.ready = (fn)->
  $(this).on 'turbolinks:load', fn
Diaconicon answered 18/11, 2016 at 8:47 Comment(1)
This is exactly what I needed. This works for external libraries that rely on document callbacks as well. Why the downvote? This should be safe as long as turbolinks is used throughout the entire application, right?Shortfall
H
3

(For coffeescript)

I Use: $(document).on 'turbolinks:load', ->

Instead of: $(document).on('turbolinks:load', function() {...})

Hardandfast answered 9/12, 2016 at 17:29 Comment(4)
I have done that and I still getting this issue as @Aleuromancy said : github.com/mkhairi/materialize-sass/issues/130. Using JS or Coffee does not really make any difference, at least NOT for me.Recognizor
Hi folks, what is wrong with this answer in general?Luing
My guess is that this is coffeescript and not native javascript? I gave it a +1 because this is exactly what I'm doing and it works for me (in my coffeescript file)Coinstantaneous
yes!, it is for coffeescript :). My mistake was not to specify itHardandfast
N
3

pure modern js:

const onLoad = () => {
  alert("works")
}

document.addEventListener("load", onLoad)
document.addEventListener("turbolinks:load", onLoad)

with turbo it's turbo:load

Nobles answered 26/11, 2020 at 19:47 Comment(0)
M
2

Here is solution that work for me, from here:

  1. install gem 'jquery-turbolinks'

  2. add this .coffee file to your app: https://github.com/turbolinks/turbolinks/blob/master/src/turbolinks/compatibility.coffee

  3. name it turbolinks-compatibility.coffee

  4. at application.js

    //= require jquery
    //= require jquery_ujs
    //= require jquery.turbolinks
    //= require turbolinks
    //= require turbolinks-compatibility
    
Medor answered 5/10, 2016 at 15:53 Comment(2)
What about in production env? Have you tested it out? There are some people telling it just work fine in development mode.Recognizor
The gem is deprecatedDigest
G
1

While we await the fix to this really cool gem, I was able to move forward by modifying the following;

  addCallback: (callback) ->
if $.turbo.isReady
  callback($)
$document.on 'turbo:ready', -> callback($)

to:

  addCallback: (callback) ->
if $.turbo.isReady
  callback($)
$document.on 'turbolinks:load', -> callback($)

I'm not yet aware what this does not resolve, but it seemed to work well on initial inspection.

Gebhart answered 11/7, 2016 at 21:37 Comment(0)
T
0

Use the light-weight gem jquery-turbolinks.

It makes $(document).ready() work with Turbolinks without changing existing code.

Alternatively, you could change $(document).ready() to one of:

$(document).on('page:fetch', function() { /* your code here */ });

$(document).on('page:change', function() { /* your code here */ });

depending on which one is more appropriate in your situation.

Threadfin answered 24/6, 2016 at 14:50 Comment(3)
jquery-turbolinks doesn't yet support Turbolinks 5 github.com/kossnocorp/jquery.turbolinks/issues/56Bookshelf
You're right, @AndrewH! Hopefully, the support will be added soon.Threadfin
The jquery-turbolinks gem has been deprecated.Melodic

© 2022 - 2024 — McMap. All rights reserved.