Tuesday, September 08, 2009

Using HTML attributes as a mini-DSL for AJAX

At first, I thought being able to return json as responses from the server was pretty neat, with rjs (now js.erb) files using render :update call in Rails.  However, this often lead to some messy code by me and my colleagues.  I would see lots of client side code in the application controller like:

Sometimes, this is ok, but when html elements change, the controller methods break, and the effect cascades from the views through the controllers.  That's a code smell that our code is tightly coupled.  Of course, we can refactor it to a separate .rjs template file, and justify it to ourselves that it's the same as having an .html.erb file.  However, because .rjs files are often so short, the cognitive shift to find that other file is often distracting, and it still doesn't solve the problem of code coupling.

Consider the following:  You want to have a link that makes an AJAX GET request to get a list of comments for the post when clicked.  It gets the response as HTML and then dumps it in the target DOM.  You also want to fade in an indicator feedback when the ajax is loading and fade it out when it's finished loading.  Lastly, there's to be a slidedown effect on the target comments DOM element.  

For the situation above, if we were to do it with render :update or with rjs files, you'd have code that is coupled with DOM elements as I said earlier.  What if we can contain it all on the client side, and leave the server side for business logic?

One way is to use all the options that link_to_remote provides.  This way, all the UI effects are contained on the client side when you have an AJAX GET request.  We can now keep all our UI effects code in the views.  

However, what if we can declare this effect in HTML?  Would that work?  What are the advantages and disadvantages?

I went to the local Ruby meetup, and remembered that Ben Johnson of Authlogic was mentioning something about "data-" attributes in HTML5 and its relation to the problem I described above.  I wasn't entirely sure what he was talking about, until I looked around for the "data- attribute" and found good ole Resig blogging about it (last year, no less).  

What this allows us to do is basically insert data into our HTML elements.  And because jQuery events let us separate the "how" in javascript from the "what" in html, we can declaratively use it as a mini-DSL of sorts.  

The basics are pretty easy to implement.  I didn't do the data-indicator and the data-effect because I'm lazy and it's left to the reader "as an exercise".

Note that I'm proposing it to be a mini-DSL, so that very common AJAX idioms are covered, and you can simply declare things in HTML and not have to go into the javascript often, if at all.  That way, you keep working in the same file, working on the same level of abstraction.

There are some advantages to doing it this way.  
  1. Server response can be faster, since we wouldn't have to rely on the server to generate the proper html link.  The UI effects and behavior can be all done on the client side, where it should be.
  2. I think it's a bit cleaner to be able to say things declaratively, more aligned with how html is declarative.
  3. The DOM elements wouldn't couple the controller and the view.  Everything that refers to DOM elements would be in the view and be easier to change without cascading effects.
  4. You can work in the same level of abstraction while in the HTML views and won't have to jump between layers of abstraction.
There are few disadvantages I can see right now, other than not having the correct DSL, or having a method call that uses too many attributes, making the HTML hard to read.  (If you have others, comment below)

Pretty neat.  So why use the class attribute as the method "call"?  Perhaps it's better to find some other attribute.  I've seen facebox use the rel attribute instead.  That lead me wonder if other people have thought to do this before.  And of course, there's something similar called AHAH microformat, based on JAH from 2005, which is demoed here.  

JAH does something notable, in that it uses the form:

to order to execute the javascript, instead of binding an event to the DOM.  This removes the extraneous href="#" in the other way I showed you above (more succinct), but it breaks the declarative nature, and cannot be unbound and binded with something else easily--one would have to change all instances it's called, instead of re-adjusting the DOM selector element (as rare as that may be).  I personally don't think it's as easy to read, especially when the method call has parameters, but the implementation would be shorter.

These techniques seem to be by no means widespread at the moment, but one of the contributors is DHH of the Rails fame, so I expect to see it in Rails soon.  So be on the lookout for something similar in the future Rails.  It seems like the technique was talked about back in 2005, but never fully incorporated or used.  I have no idea why.  In the mean time, I intend to incorporate it into new code I write.

(Apologies if there are typos above.  It's late, and I haven't had my ramen)

Posted via email from The Web and all that Jazz

No comments:

Post a Comment