Reputation: 33785
So I have a button that I press that executes some JS. But what is happening is on the first load of the page it works, but once I go to another page and press the button on that new page, it doesn't work.
Per the Turbolinks documentation, this is normal - so I have to make a modification.
This was partially covered in this RailsCast - http://railscasts.com/episodes/390-turbolinks?view=asciicast - but the solution that Ryan gives is in CoffeeScript and I am using plain old vanilla JS.
This is my posts.js
file:
$(function(){
var toggleSidebar = $("#togglesidebar");
var primary = $("#primary");
var secondary = $("#secondary");
toggleSidebar.on("click", function(){
if(primary.hasClass("col-sm-9")){
primary.removeClass("col-sm-9");
primary.addClass("col-sm-12");
secondary.css('display', 'none');
}
else {
primary.removeClass("col-sm-12");
primary.addClass("col-sm-9");
secondary.css('display', 'inline-block');
}
});
});
$(document).on('page:load');
Per RailsCasts, this is what they suggest:
ready = ->
$('.edit_task input[type=checkbox]').click ->
$(this).parent('form').submit()
$(document).ready(ready)
$(document).on('page:load', ready)
When I try this at the bottom of my posts.js
:
$(document).ready();
$(document).on('page:load', ready());
I get this error:
Uncaught ReferenceError: ready is not defined
Thoughts on how I can get this? I am pretty sure it is simple, but I have very little JS experience and even less with CoffeeScript.
Upvotes: 4
Views: 1881
Reputation: 76784
You've got your answer, let me explain it:
--
Turbolinks
When your application runs Turbolinks, it essentially makes it so that every Turbolinks-enabled link you follow will just render the <body>
of the requested page, leaving the <head>
tags intact
The <head>
tags are where your <script>
tags reside, meaning that they don't get refreshed when Turbolinks is called. This might not seem like a big deal; it is.
The problem you have is that JS only binds to elements at load, meaning that any new elements which are appended to the page will not be bound with any events:
...
This means that if you want to perform any sort of action with your application's JS, you need to accomodate the fact that the <body>
tag is going to constantly change.
To do this, you can use two methods:
- Javascript Delegation
- Turbolinks events
The first method is to delegate your events from a "consistent" element (typically $(document)
). This works by allocating your JS to a container
element, and then allowing it to "delegate" that down to the element you want. The best example of this is the .on
function:
$(document).on("click", "a", function(){
alert("Clicked");
});
Secondly, you'll want to look at the Turbolinks event hooks - this is what you're using now. These override many of the standard JQuery functions (such as $(document)
), allowing you to call the functions you have as follows:
var your_function = function(){
...
};
$(document).on("page:load ready", your_function);
Upvotes: 5
Reputation: 3410
If you're using JS, not CoffeeScript, why you have ready = ->
in your JS file?
Try this.
var ready;
ready = function() {
$('.edit_task input[type=checkbox]').click(function() {
$(this).parent('form').submit();
});
};
$(document).ready(ready);
$(document).on('page:load', ready);
In your case:
var ready;
ready = function() {
var toggleSidebar = $("#togglesidebar");
var primary = $("#primary");
var secondary = $("#secondary");
toggleSidebar.on("click", function(){
if(primary.hasClass("col-sm-9")){
primary.removeClass("col-sm-9");
primary.addClass("col-sm-12");
secondary.css('display', 'none');
}
else {
primary.removeClass("col-sm-12");
primary.addClass("col-sm-9");
secondary.css('display', 'inline-block');
}
});
};
$(document).ready(ready);
$(document).on('page:load', ready);
Upvotes: 1