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

application.js page.alert 'This would show for all pages'

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

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

DAZ

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?

DAZ

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:

Event.addBehavior({   ".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...

http://www.danwebb.net/2006/9/3/low-pro-unobtrusive-scripting-for-prototype

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: http://hosting.media72.co.uk/blog/2008/05/13/javascript-auto-include-rails-plugin/

Geoff

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 like:

Event.addBehavior({   ".sortable" : Sortable.Element

})

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

DAZ

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.

Hi,

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 tricky.

Thnks for any help

Tonypn