Observing Fields With Rails in the Browser

Posted by Rick DeNatale Sun, 07 Oct 2007 16:34:00 GMT

The AJAX support in Rails is great, but sometimes you don't want to have to make an unnecessary trip to the server to make your UI dynamic. For example, let's say you want to do something like Basecamp does when you create a new message. If you have a Basecamp setup to allow you to talk to both members of your team and also clients, it provides some nice checkboxes to let you control who will get notified of the new message. Those checkboxes are grouped with a checkbox for each company, and then checkboxes for all of the people from that company below the company checkbox. If you check or uncheck a company checkbox all of the people listed under the company are checked or unchecked to match.

This can all be done within the browser. It just requires manipulation of existing elements within the domain object model, so there's no need to go back to the server.

Rails provides the observe_field helper method which is normally used to generate a remote request when a DOM element changes. It can be used to do what we want, but how to do so isn't well documented, either in the Rails documentation, or via google.

So here's how to do it.

What the Rails Doc says

Here's how the official doc for observe_field starts...

observe_field(field_id, options = {})

Observes the field with the DOM ID specified by field_id and calls a callback when its contents have changed. The default callback is an Ajax call. By default the value of the observed field is sent as a parameter with the Ajax call.

Required options are either of:

:url:url_for-style options for the action to call when the field has changed.
:function:Instead of making a remote call to a URL, you can specify a function to be called instead.

So the function option seems to be what we need When I read this I assumed that the value should be a string containing a javascript function definition. But it's not.

What the value should be is javascript code for the body of the function definition. The prototype helper provides the surrounding definition. So when you code:

        
observe_element('company1', :function => 'code')
The javascript code generated looks like:
Form.Observer.new('company1', function(element,value) {code})

So just write Javascript code for the body. You can use the element parameter to refer to the domain element being observed, in this case it would be the same as the prototype expression "$('company1')" and the value parameter gives you the value attribute of the observed element.

So let's say our company has two guys whose checkboxes are 'bill_c' and 'sam_r' and our company checkbox is called 'our_corp'. Then this helper call:
        
observe_element(
    'our_corp', 
    :function => "$('bill_c') = value\n$('sam_r') = value")

Should do the trick of turning both the bill_c and sam_r checkboxes on or off when we toggle the our_corp checkbox.

Of course you probably don't want to hand code the ids, and the actual ids will conform to those used by the form helpers, but I'll leave those details to you

Getting the Rails Docs Updated

I've submitted a ticket on rails trac with a patch to document this. If you've got a rails trac account, please have a look and consider adding a +1 to get this into report #12 and into Rails.

Posted in  | Tags ,  | 1 comment | no trackbacks

Comments

  1. James O'Kelly said about 13 hours later:

    Very nice find! I too have been struggling with how to minimize my database hits when they are not needed. While javascript can be a bitch (can I say that here?) because fo browser dom differences, the extra care taken to write good javascript to do the job instead of making another request call, I’d say it can be well worth it.

    I’ll be looking into this more.

Trackbacks

Use the following link to trackback from your own site:
http://talklikeaduck.denhaven2.com/articles/trackback/468

Comments are disabled