Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper "Rails" way to perform javascript on specific pages

I'm attempting to run javascript on specific pages and my only solution seems like an anti-pattern. I have controller.js generated inside of assets/javascripts/. I'm using gem 'jquery-turbolinks' I have code resembling the following:

$(document).ready(function () {
    //Initiate DataTables ect..
    }
)

This code is firing on every page So I added the following inside of it.

if ($('#page-specific_element').length > 0) {
    //Initiate Datatables ect.
}

My question being, is there a way to set rails to utilize only the javascript files necessary to a specific controller or is logic gating behind an element search the best solution?

like image 736
Maleki Avatar asked May 08 '15 22:05

Maleki


2 Answers

This is a pretty nice turbolinks specific solution:

<body data-controller="<%= controller.controller_name %>" data-action="<%= controller.action_name %>">

// Instead of listening for document ready
$(document).on('users#show:loaded', function(){
    $('#logger').append('<li>Users Show action loaded</li>');
});

// Instead of listening for document ready
$(document).on('users:loaded', function(){
    $('#logger').append('<li>Some users controller method loaded</li>');
});

// Turbolinks fires "page:change" when it changes the page content.
// you could change this to just document ready if you are not using 
// turbolinks.
$(document).on("page:change", function(){
  var data = $('body').data();
  $(document).trigger(data.controller + ':loaded');
  $(document).trigger(data.controller + '#' + data.action + ':loaded');
});

// This is just for demonstration purposes...
$(document).trigger("page:change");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body data-controller="users" data-action="show">

  <ul id="logger"></ul>
</body>

You should note that if you are using Turbolinks that you'll have a long-running, persistent session with maintained state. Which means that if you add inline script tags or load additional javascript files in your views they will linger in the browsers memory.

You therefore might therefore want to cleanup whatever page specific event handlers you have created on page:before-unload.

like image 148
max Avatar answered Oct 22 '22 05:10

max


There are many ways to do this. I'll describe one.

I use this old gem to wrap all my .module.js files in commonjs modules.

I then have a helper that writes something like the following to a <script> tag in the head of every HTML page.

<script>
  var App {
    pageModule: 'posts/create'
  };
</script>

posts/create is generated from a simplified mix of the current controller and action rendering the request.

I then have something like the following in my domready for my application.js.

try { App.pageModule = require(App.pageModule); } catch(e) { console.log('%c' + e, 'color:red; background-color:yellow'); }

if (_.isPlainObject(App.pageModule) && _.has(App.pageModule, 'initialize')) {
  App.pageModule.initialize();
}

Finally, I'll have a file like this which is specific to the /posts/create URL.

app/assets/posts/create.module.js

module.exports = {

  initialize: function() {
    // data-tables stuff here...
  }

}
like image 40
deefour Avatar answered Oct 22 '22 05:10

deefour