# Unobtrusive Javascript

**URL:** <https://www.ruby-forum.com/t/unobtrusive-javascript/138949>\
**Category:** Rails\
**Created:** [May 29, 2008, 9:32am UTC](https://www.ruby-forum.com/t/unobtrusive-javascript/138949 "2008-05-29T09:32:21Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![daz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/87869e/32.png) [@daz](https://www.ruby-forum.com/u/daz)\
**Post date:** [May 29, 2008, 9:32am UTC](https://www.ruby-forum.com/t/unobtrusive-javascript/138949/1 "2008-05-29T09:32:21Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![daz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/87869e/32.png) [@daz](https://www.ruby-forum.com/u/daz)\
**Post date:** [May 29, 2008, 11:03am UTC](https://www.ruby-forum.com/t/unobtrusive-javascript/138949/2 "2008-05-29T11:03:24Z")

</div>

Looks like a lot of overhead to me.

Ok, this may depend on project sizes, so I can only speak for what we do  
in our company. We do projects the size around 30 controllers, 25  
models.

We don’t use helpers that much. Most of them go into  
application\_helper.rb, since they’re used everyther, eg to format  
prices.

Same would go to javascripts.  
There are all the “big” files like prototype that are used everywhere.  
No need to seperate them.  
Then there would be some special cases, like calendars or swfupload.  
They’re only used where we need them. But that’s around five of them and  
they can be handled easy enough.

Then there would be detail stuff for single types of pages. But those  
are used more on the action level then controller (eg anything to do  
with tables is more likely to be needed in every index action then in a  
specific controller)  
For this kind of js you can use partials or include them depending on  
controller or action name. (content\_for)

I don’t think there is a great need for a complete controller related js  
folder structure like we have for the helpers.

---

<div class="post-metadata">

**Author:** ![daz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/87869e/32.png) [@daz](https://www.ruby-forum.com/u/daz)\
**Post date:** [May 29, 2008, 11:39am UTC](https://www.ruby-forum.com/t/unobtrusive-javascript/138949/3 "2008-05-29T11:39:15Z")

</div>

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

On May 29, 10:03 am, Thorsten M. \<rails-mailing-l…@andreas-

---

<div class="post-metadata">

**Author:** ![daz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/87869e/32.png) [@daz](https://www.ruby-forum.com/u/daz)\
**Post date:** [May 29, 2008, 12:53pm UTC](https://www.ruby-forum.com/t/unobtrusive-javascript/138949/4 "2008-05-29T12:53:24Z")

</div>

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](http://www.danwebb.net/2006/9/3/low-pro-unobtrusive-scripting-for-prototype)

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

---

<div class="post-metadata">

**Author:** ![daz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/87869e/32.png) [@daz](https://www.ruby-forum.com/u/daz)\
**Post date:** [May 29, 2008, 4:20pm UTC](https://www.ruby-forum.com/t/unobtrusive-javascript/138949/5 "2008-05-29T16:20:32Z")

</div>

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

On May 29, 11:53 am, Nathan E. \<rails-mailing-l…@andreas-

---

<div class="post-metadata">

**Author:** ![daz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/87869e/32.png) [@daz](https://www.ruby-forum.com/u/daz)\
**Post date:** [May 29, 2008, 2:11pm UTC](https://www.ruby-forum.com/t/unobtrusive-javascript/138949/6 "2008-05-29T14:11:22Z")

</div>

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

Geoff

On May 29, 11:53 am, Nathan E. \<rails-mailing-l…@andreas-

---

<div class="post-metadata">

**Author:** ![daz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/87869e/32.png) [@daz](https://www.ruby-forum.com/u/daz)\
**Post date:** [May 29, 2008, 5:26pm UTC](https://www.ruby-forum.com/t/unobtrusive-javascript/138949/7 "2008-05-29T17:26:23Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![daz](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/87869e/32.png) [@daz](https://www.ruby-forum.com/u/daz)\
**Post date:** [June 14, 2008, 10:00am UTC](https://www.ruby-forum.com/t/unobtrusive-javascript/138949/8 "2008-06-14T10:00:22Z")

</div>

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
