89

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?

Community
  • 1
  • 1
AndrewH
  • 3,248
  • 2
  • 12
  • 26

9 Answers9

175

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!")
})
AndrewH
  • 3,248
  • 2
  • 12
  • 26
  • 6
    Yes. Explained here as well. http://guides.rubyonrails.org/working_with_javascript_in_rails.html#turbolinks. Check 5.2 Page Change Events. – Indika K Jul 10 '16 at 06:58
  • 3
    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. – psparrow Sep 22 '16 at 16:03
  • this not work well. I have a select2 and when change the page and back I have two select2 (duplicated) – inye Oct 18 '16 at 17:00
  • Yes that's true @inye I have the same issue and I also have opened a issue at [GitHub](https://github.com/mkhairi/materialize-sass/issues/130). Have you solved somehow? – alexventuraio Dec 16 '16 at 06:55
  • 3
    Despite what the Rail doc says, I'm using `on('ready turbolinks:load')` otherwise I have some problems on some pages – Cyril Duchon-Doris Dec 22 '16 at 11:31
  • 1
    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, http://stackoverflow.com/questions/41421496/turbolinks-load-event-not-working-on-with-page-refresh. 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. – Obromios Jan 06 '17 at 06:23
  • For me, `$(document).on('turbolinks:load', ...)` did _not_ work; I had to use `document.addEventListener('turbolinks:load', ...` as described in the [Turbolinks README](https://github.com/turbolinks/turbolinks/blob/master/README.md#running-javascript-when-a-page-loads). – bovender Jan 31 '17 at 05:07
  • @bovender 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. – Beartech Apr 04 '17 at 18:54
  • and could be used as following: ```$(document).on 'ready, turbolinks:load', ->``` ? – user1136228 Sep 26 '17 at 18:41
  • @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() {} ) })` – Crimbo Nov 21 '19 at 13:32
  • 1
    Is this different for rails 6? – stevec Sep 26 '20 at 12:45
64

Native JS :

document.addEventListener("turbolinks:load", function() {
    console.log('It works on each visit!');
});
Vadim
  • 1,650
  • 2
  • 17
  • 31
Siamko
  • 809
  • 7
  • 3
13

In rails 5 the easiest solution is to use:

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

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

Milad.Nozari
  • 2,063
  • 2
  • 21
  • 44
  • 10
    Don't add `ready` to the list, otherwise the function will be executed twice. As https://github.com/turbolinks/turbolinks/#observing-navigation-events said, you should do it like this: ```javascript $(document).ready(function() { $(document).on('turbolinks:load', function() {} ) }) ``` – Xiaohui Zhang Dec 30 '18 at 08:43
  • @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:load` – Milad.Nozari Dec 31 '18 at 06:20
  • @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 code – escanxr Sep 05 '19 at 09:31
  • @escanxr It works both, you can try it out. because Turbolinks always trigger "turbolinks:load" event whenever a Turbolinks page or not. – Xiaohui Zhang Sep 06 '19 at 17:45
  • 2
    @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 twice – escanxr Sep 07 '19 at 22:22
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
Xiaohui Zhang
  • 777
  • 7
  • 11
  • 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? – Dylan Vander Berg Jun 12 '17 at 15:48
3

(For coffeescript)

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

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

fcabanasm
  • 83
  • 5
  • I have done that and I still getting this issue as @inye said : https://github.com/mkhairi/materialize-sass/issues/130. Using JS or Coffee does not really make any difference, at least NOT for me. – alexventuraio Dec 16 '16 at 07:22
  • 2
    Hi folks, what is wrong with this answer in general? – atw Nov 22 '18 at 15:26
  • 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) – aarona May 28 '19 at 16:07
  • yes!, it is for coffeescript :). My mistake was not to specify it – fcabanasm May 29 '19 at 17:08
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
    
ChaosPredictor
  • 2,885
  • 1
  • 24
  • 35
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.

1

pure modern js:

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

document.addEventListener("load", onLoad)
document.addEventListener("turbolinks:load", onLoad)
Dorian
  • 1,551
  • 8
  • 23
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.

Vadim
  • 1,650
  • 2
  • 17
  • 31