I currently have the following script in two of my form views.
<script>
$('#standard_calendar').calendar();
$('#time_calendar').calendar({type: 'time'});
</script>
Where I can place them so they're accessible but not mixed in with my HTML?
Your scripts should ideally be prepackaged and concatenated into a single file to avoid multiple HTTP requests. Instead of relying on loading a particular set of JavaScript on a specific page you can just add a data attribute or class to the body element and use it to toggle your behaviors. This is not only better for performance but will avoid the issues tied to turbolinks and having a persistent browser session across page visits.
I wrote a gem for this a while back that has not been maintained in quite some time but I solved it by basically doing:
<body data-action="<%= action_name %>" data-controller="<%= controller_name %>">
$(document).on('turbolinks:load', function(){
let data = $('body').data();
// pagescript: is just the namespace for the events to avoid potential name collisions
// Use whatever you want instead
$(document).trigger('pagescript:' + data.controller + '#' + data.action, data)
.trigger('pagescript:' + data.controller + '#*', data)
.trigger('pagescript:' + '*#' + data.action , data);
});
This triggers a set of custom events on every page change. You can add event listeners to listen for specific pages or actions:
// A specific controller_name and action
$(document).on('pagescript:controller_name#action_name', (e) => { });
// Any action belonging to a specific controller
$(document).on('pagescript:controller_name#*', (e) => { });
// Any action matching action_name
$(document).on('pagescript:*#action_name', (e) => { });
For example:
$(document).on('pagescript:users#new', (e) => {
alert("Welcome new user!");
});
But the problem can also be solved by better code design. Think in terms of modules that can be used to enhance the behavior in any page instead of writing code that enhances that specific doodad on the specific page.
You have two options (I assume you have webpacker installed):
app/javascript/components folder. And then import this file into the application.js. application.js is the entry point for all javascript - through <%= javascript_pack_tag 'application' %> in application.html.erb. So then your script will be called on all pages.app/javascript/packs and then in the respective view, you call your script with <%= javascript_pack_tag 'file_name' %>. So if you call your file calendar.js it would be <%= javascript_pack_tag 'calendar' %> Then your script will only be called on this one view page.One more hint if you follow the second option and if you have the main <%= javascript_pack_tag 'application' %> in application.html.erb at the bottom:
This would mean, that you call your calendar script before you render the main application.js which could lead to bugs. A way to avoid that is to create a second yield in application.html.erb and use it like so:
application.html.erb
<body>
<%= yield %>
<%= render "shared/footer" %>
<%= javascript_include_tag 'application' %>
<%= javascript_pack_tag 'application' %>
<%= yield(:after_js) %>
</body>
And then in your view you can do the following:
views/somthing/index.html.erb
...
<%= content_for :after_js do %>
<%= javascript_pack_tag 'calendar' %>
<% end %>
This flow would be the following: application.html.erb is rendering the body and including the html code from the view files. Then it renders a footer (for example). It then calls application.js which might import some general JS code and packages. And then the second yield calls the block in the view again which has the specific script for the calendar.