No commit activity in last 3 years
No release in over 3 years
Auto-magical scaffolding for Paul Irish's DOM-based Routing way of organizing your javascript.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
 Project Readme

DomRoutes

Auto-magical scaffolding for Paul Irish's DOM-based Routing (or Garber-Irish Implementation) way of organizing your javascript.

Works with turbolinks

Purpose

Javascript is hard to organize and debugging ajax is a mess. This is one method to organizing your javascript neatly by mirroring the controllers and having all the it outside of your HTML views.

How it works

Setup your namespace

DR.routes = {
	all: {
		html: {
			before: function() {
			}
		}
	},
	demos: {
		html: {
			before: function() {
			},
			demo_action: function() {
			}
		}
	}
}

What happens

After, requests to demos#demo_action with format html will call the following functions (if they exist):

  • DR.routes.application.html.before
  • DR.routes.demos.html.before
  • DR.routes.application.html.demo_action
  • DR.routes.demos.html.demo_action
  • DR.routes.demos.html.after
  • DR.routes.application.html.after

js format is also supported, i.e.:

  • DR.routes.application.js.before
  • DR.routes.demos.js.before
  • DR.routes.application.js.demo_action
  • DR.routes.demos.js.demo_action
  • DR.routes.demos.js.after
  • DR.routes.application.js.after

Installation

Add this line to your application's Gemfile:

gem 'dom_routes'

And then execute:

$ bundle

Add this to your app/assets/javascripts/application.js

//= require dom_routes

Make sure your app/views/layouts/application.html.erb (and all your other layouts) looks like this:

<html>
<head>...</head>
<body data-controller="<%= js_route.controller_path %>" data-action="<%= js_route.action %>"><%= execute_js_routes %>
</body>
</html>

Basic Use

I like to have a JS file for every route in app/assets/javascripts/routes. Like so:

app/assets/javascripts/routes/demos.js:

(function() {
	var demos = DR.define('demos', {
		html: {
			edit: function(params) {
				alert(params.alert_message);
			}
		},

		js: {
			new: function(params) {
				console.log(params.log_message);
			}
		}
	});
})();

DR.define() extends or creates the namespace DR.routes.demos and returns it. This allows me to access DR.routes.demos through the demos variable. You can also use the traditional hash namespacing shown in the Setup your namespace section.

So if a html request is sent to demos#edit, DR.routes.demos.html.edit is called with the HTML view rendering.

For a js request sent to demos#new, DR.routes.demos.js.new is called and nothing else happens.

Templates and parameters

Optional Parameters are passed from a JSON DSL (such as jbuilder) and is passed as the params object to the function. You can pass any JSON object as a template.

HTML

app/views/demos/edit_params.js.jbuilder:

json.alert_message "ploop"

so

DR.routes.demos.html.edit({ alert_message: "ploop" });

is called automatically.

Javascript

For javascript to work, a template must exist. app/views/demos/new.js.jbuilder:

json.log_message "loggggggggggggg"

so

DR.routes.demos.js.new({ log_message: "loggggggggggggg" });

is called automatically.

Advanced Use

Manually execute a route

Use #execute_js_route(js_route=self.js_route, format=formats.first)

Executing a different route

Sometimes you want to execute a different route too. For that, you can specify it like so:

self.js_route = "demos/edit" # can be "demos#edit", "edit", { controller: "demos", action: "edit" }, or a DomRoutes::Route object

When this is done, the original route and the new route will be executed.

Handling redirects with flash

Other times you may want to use a route after a redirect, use #flash_js_route(js_route=nil) then.

Credits

Extracted out of Placemark. Originally called poke_js.

Contribution

Feel free to fork, post issues or send any pull requests. Thanks.