#74 Page Specific Javascript in Ruby on Rails
4/2/2017

Summary

Sometimes you may find yourself with an application that has javascript that needs to execute only on a specific page. This episode lays the foundation to easily manage page specific javascript.
10
rails javascript view 4:44 min

Summary

application.html.erb# use either the meta tag or body's data attributes.
<head>
  ...
  <%= tag :meta, name: :psj, action: action_name, controller: controller_name %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  ...
</head>

<%= content_tag :body, data: { action: action_name, controller: controller_name } do %>
  ...
<% end %> 
app/javascripts/init.coffeeclass Page
  controller: () =>
    $('meta[name=psj]').attr('controller')
    # $('body').data('controller')
  action: () =>
    $('meta[name=psj]').attr('action')
    # $('body').data('action')

@page = new Page

# Javascript equivalent

var Page, bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
Page = (function() {
  function Page() {
    this.action = bind(this.action, this);
    this.controller = bind(this.controller, this);
  }
  Page.prototype.controller = function() {
    return $('meta[name=psj]').attr('controller');
  };
  Page.prototype.action = function() {
    return $('meta[name=psj]').attr('action');
  };
  return Page;
})();
this.page = new Page;
visitors.coffee$(document).on 'turbolinks:load', ->
  return unless page.controller() == 'visitors' && page.action() == 'index'
  # return unless $('meta[name=psj]').attr('controller') == 'visitors' # && $('meta[name=psj]').attr('action') == 'index'
  # return unless $('body').data('controller') == 'visitors' && $('body').data('action') == 'index'
  $('main').append '<li>Hello from visitors</li>'

# Javascript equivalent

$(document).on('turbolinks:load', function() {
  if (!(page.controller() === 'visitors' && page.action() === 'index')) { return; }
  return $('main').append('<li>Hello from visitors</li>');
});
app/javascripts/users/index.coffee$(document).on 'turbolinks:load', ->
  return unless page.controller() == 'users' && page.action() == 'index'
  $('main').append '<li>Hello from users index</li>'

# Javascript Equivalent

$(document).on('turbolinks:load', function() {
  if (!(page.controller() === 'users' && page.action() === 'index')) { return; }
  return $('main').append('<li>Hello from users index</li>');
});
app/javascripts/users/users.coffee$(document).on 'turbolinks:load', ->
  return unless page.controller() == 'users' 
  $('main').append '<li>Hello from users controller</li>'

# Javascript Equivalent

$(document).on('turbolinks:load', function() {
  if (page.controller() !== 'users') { return; }
  return $('main').append('<li>Hello from users controller</li>');
});
2021570?v=3&s=64
ninoM said 8 months ago:

Thanks for providing the JS equivalent code!

8439131?v=4&s=64
selzlein said 9 days ago:

Great work, thank you!

I have implemented the controller action specific CoffeeScript approach. Therefore I have 1 .coffee file per controller action. However I stumbled upon an issue... let's say I have a controller with a 'new' action and a respective 'new.coffee' script. When I submit the 'new' page that triggers Rails validation errors, the controller action gets updated to 'create', since it was a Post. Therefore 'new.coffee' won't execute while my controller renders 'new.html.erb' directly, not through a redirect, as is standard Rails scaffold.

In this case what would you recommend? Should I simply use the 1 file per controller approach?

635114?v=3&s=64
kobaltz PRO said 9 days ago:

You could mix and match based on the complexity of the JS needed. You could also look at something like client side validations to prevent the form from posting if the data isn’t valid (but not recommended for uniqueness validations because of potential security reasons).

8439131?v=4&s=64
selzlein said 9 days ago:

Got it! Thank you :D

Login to Comment