Rails 4: how to use $(document).ready() with turbo
I ran into an issue in my Rails 4 app while trying to organize JS files "the rails way". They were previously scattered across different views. I organized them into separate files and compile them with the assets pipeline. However, I just learned that jQuery's "ready" event doesn't fire on subsequent clicks when turbo-linking is turned on. The first time you load a page it works. But when you click a link, anything inside the ready( function($) {
won't get executed (because the page doesn't actually load again). Good explanation: here.
So my question is: What is the right way to ensure that jQuery events work properly while turbo-links are on? Do you wrap the scripts in a Rails-specific listener? Or maybe rails has some magic that makes it unnecessary? The docs are a bit vague on how this should work, especially with respect to loading multiple files via the manifest(s) like application.js.
Here's what I do... CoffeeScript:
ready = ->
...your coffeescript goes here...
$(document).ready(ready)
$(document).on('page:load', ready)
last line listens for page load which is what turbo links will trigger.
Edit ...adding Javascript version (per request):
var ready;
ready = function() {
...your javascript goes here...
};
$(document).ready(ready);
$(document).on('page:load', ready);
Edit 2 ...For Rails 5 (Turbolinks 5) page:load
becomes turbolinks:load
and will be even fired on initial load. So we can just do the following:
$(document).on('turbolinks:load', function() {
...your javascript goes here...
});
I just learned of another option for solving this problem. If you load the jquery-turbolinks
gem it will bind the Rails Turbolinks events to the document.ready
events so you can write your jQuery in the usual way. You just add jquery.turbolinks
right after jquery
in the js manifest file (by default: application.js
).
Recently I found the most clean and easy to understand way of dealing with it:
$(document).on 'ready page:load', ->
# Actions to do
OR
$(document).on('ready page:load', function () {
// Actions to do
});
EDIT
If you have delegated events bound to the document
, make sure you attach them outside of the ready
function, otherwise they will get rebound on every page:load
event (causing the same functions to be run multiple times). For example, if you have any calls like this:
$(document).on 'ready page:load', ->
...
$(document).on 'click', '.button', ->
...
...
Take them out of the ready
function, like this:
$(document).on 'ready page:load', ->
...
...
$(document).on 'click', '.button', ->
...
Delegated events bound to the document
do not need to be bound on the ready
event.
上一篇: REST身份验证方案的安全性