Rails controller based javascript to keep your javascript outside of your views.
Based off Paul Irish's DOM-based Routing (or Garber-Irish Implementation). Works with turbolinks.
How it works
Jcontroller.create('users', {
html: {
// executes whenever users#index with html format is executed
index: function() {}
}
});
No other code is needed.
Installation
Add gem 'jcontroller'
to your application's Gemfile
and run the bundle
command, then add this to your app/assets/javascripts/application.js
//= require jcontroller
Controllers
Namespaces
Jcontroller creation and finding are based off the controller path.
// for Admin::UsersController
Jcontroller.create('admin/users', {});
Filters
Jcontrollers can be created with before and after filters like so:
Jcontroller.create('users', {
html: {
// executes for all html format responses for UsersController, before the specific action
before: function() {},
// executes whenever users#index with html format is executed
index: function() {},
// executes for all html format responses for UsersController, after the specific action
after: function() {}
}
});
Inheritance
By default, jcontrollers inherit from the application
jcontroller and will execute it if it exists, such as:
Jcontroller.create('application', {
html: {
before: function() {},
index: function() {},
after: function() {}
}
});
So with the jcontrollers above the order of execution is:
application.before
users.before
application.index
users.index
application.after
users.after
You can also set your own inhertance chain:
Jcontroller.create('users', {
parent_path: 'users_base',
...
});
API
- Parameters are accessed from
this.params
or as the first parameter - The request state (controller_path, action_name, jcontroller, etc.) are also given in
this.state
or the second parameter - And other methods to work with jcontrollers
Jcontroller.create('users', {
html: {
index: function(params, state) {
//this.params === params
console.log(this.params);
//this.state === state
console.log(this.state);
var jcontroller = JController.find('application');
self.parent(); // === jcontroller
//excute application_jcontroller for this state and params again
jcontroller.execute_jaction(this.params, this.state);
//execute application_jcontroller html.index function
jcontroller.html.index();
}
}
});
With ruby, you could also access the state in jaction
to make action specific CSS:
<body data-controller="<%= jaction.controller_path %>" data-action="<%= jaction.action_name %>">
...
</body>
Organization
I like having a jcontrollers directory and calling my files as jcontroller files (ex. users_jcontroller.js).
Parameters
Manual
Use the js
method with the params
option.
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
js { :params => { :id => @user.id } }
end
end
From view template
You can also create parameters using a JSON DSL (such as jbuilder) by creating a template named <action_name>_params.js.<DSL suffix>
:
# app/views/users/show_params.js.jbuilder
json.id @user.id
Controlling javascript execution
Stop
Stop all execution of all filters and methods for the action:
class UsersController < ApplicationController
def index
js false
end
end
Different jcontroller
Execute a different jcontroller:
class UsersController < ApplicationController
def index
# same as "users#index.html", parameters and options are optional
js "users/show.html", { :params => { ... } }
end
end
HTML view
Execute all filters and actions related to a action:
<!-- same as "users#index.html", parameters and options are optional -->
<%= execute_jaction "users/show.html", { :params => { ... } } %>
Manually filter in Javascript
You can use the given state to stop execution of functions:
Jcontroller.create('application', {
html: {
before: function() {
if (this.state.action_name === 'destroy') { }
}
}
});
Redirect
You can execute all filters and functions of the current action before the redirected action using:
class UsersController < ApplicationController
def index
js { :redirect => true }
redirect_to user_path(User.first)
end
end
So users/index.html
will be executed before users/show.html
.
Ajax
You can optionally execute jcontrollers for ajax instead of writing javascript in views by turning it in config/application.rb
:
Jcontroller.ajax = true
Jcontrollers will automatically execute with parameters given by the template with a JSON DSL:
# app/views/users/show.js.jbuilder
json.id @user.id
Credits
Extracted out of Placemark. Originally called dom_routes. An alternative is paloma.