Unobtrusive Javascript

Something that has always bugged me about rails are the JavaScript
helpers. They are brilliant in what they do, but create some fairly
nasty looking inline javascript. Everything else in rails is nicely
separated, but the JavaScript isn't. There have been a few attempted
solutions such as the UJS plugin, but I don't think that that is
supported anymore.

How about this idea I've had:

There is a javascripts folder that works a bit like the helpers
folder. In here you have application.js where any site-wide JS goes,
you also have JS files named after each model (e.g. 'products.js')
where you can put javascript that only applies to pages for that
model. If you want to add specific JS to just one action then put
these inside method definitions.

These JS files would automatically be loaded for each page they
applied to.If they could be written in RJS then even better!

e.g. - inside the javascripts folder

page.alert 'This would show for all pages'

page.alert 'This would show for all product pages'
def index
page.alert 'This would only show on the product index page'

Is this possible? Could it work? What do people think?


Thanks for the reply Thorsten. Yes it makes sense that it would be a
large amount of overhead to achieve this. I still think that rails
hasn't really addressed unobtrusive javascript effectively, which is a
shame as it follows best practice in so many other areas.

I think the solution might be in using :content_for to add the
relevant js files when required and perhaps using the .js.erb
templates to get some added ruby functionality?


I have been using lowpro for months. It is a godsend. I agree that the
javascript helpers are ugly and obtrusive...

old way:

link_to_remote "test", :url => route_url

turns into

<a href="#" onclick="new Ajax.Request(...huge text...)"

very obstrusive...

with lowpro:

link_to "test", route_url, :class => "remote"

and in app.js:

  ".remote" : Remote.Link

completely unobstrusive.

Same works for remote forms, observers and lots more and you can easily
define your own behaviors...

Trust me try it...

2 Dan Webb: Thanks for an awesome library in case you one day come
across this post.

I've been more recently using content_for :javascript and then
emitting that javascript code into the application layout template. It
works well and only really clutters up the head of your document.

Also Media72 recently released a plugin which auto includes
controller_name.js and controller_name/action_name.js files provided
they exist under public/javascript/views/ which works very well with
the possible exception of form partials in which you'd need to
duplicate js for edit/new actions.

Media72's javascript_auto_include plugin:


I've seen a bit of Low Pro, but not looked at it enough. Does that
mean that if I give a ul a class of sortable, I could do something

  ".sortable" : Sortable.Element


...Because that is exactly what I'm looking for.....


That is exactly the point of lowpro. You define a behavior class and
then you can apply it to any number of elements via the css selector at
once. Also, not only that but the events are bound even after ajax calls
modify the page making it even more powerful.

The strength of LowPro is being able to define new events to easily. I
don't know if "Sortable" is a built in behavior but:

Remote.Link, Remote.Form, Observed, Draggable, In Place Editor, and Auto
Complete are all available in lowpro svn. Using these examples you can
create any behaviors you want.


I am just working on a view where I want to manage field (tabl-cell)
data entry on a cell by cell clickable basis and was looking for a way
to manage the events without creating a large number of observers and
not adding onclick events to every td cell. In fact I was thinking it
would be nice to be able to alter the action of the event depending
on circumstances. eg. handle a click event differently depending on
whether a cell is already open for editing. I was thinking it should
be possible to create javascript code that would know if another cell
is open for edit by the fact that it now contains a text box. eg. if
text box class edit exists then make a different remote call,
returning the value of the txt box. If it is not open then make a
call to open a text box in the element clicked.

In looking into this I came acrosss unobtrusive javascript concept
which to be honest I had not looked into before. It is very appealing
and seems to fit what I am trying to do very well.

I have looked at Low Pro and other sources, but most examples relate
to handling page effects etc. I wondered if you guys might know of a
tutorial or perhaps offer a bit of sample code that would help me
piece it together.

From what I have read so far, it seems to me that an approach might be
to detect the click at the table level (or by td class), then in the
handler find the element that has been clicked.
Get the id for the element and make a remote call.
If there is already an element open for edit (id the text box exists)
then inlclude the id and value of the element that is open for edit.

Now on the server side, I dont need to remember any state
information. If someone clicks away from the current edit box, then
the remote call will contain all the necessary info to allow the
current edit bo to be replaced by a normal td, and the new edit box to
be opened at the td that has been clicked.

I have done something along these lines by manging it server side, but
things can get out of step, and also clicking away from an active
(editable) element can get out of step. Also, there is the handling
of two events, the onchange or blur of the current box and the onclick
event for the new box.

Just seems to me that managing this client side is far safer and
tidier. But I am not javascript fluent and so am finding it a bit

Thnks for any help