*

2006 / February 20/ AJAX Tamed: Where HTML and the DOM meet

AJAX is a powerful technology and frameworks like Prototype and Dojo have made it frighteningly easy to hack together some AJAX support for your very own app in a matter of minutes. The problem, as described by dozens of people has been the lack of direction, resulting in more tag soup. The tools are out there, ready for use: but how does it all fit together?

HTML, CSS, and DOM Scripting

HTML is the language of the world wide web. Good HTML should be semantic and work without the aid of any Javascript or CSS. The idea of separation of structure, style, and behavior has divided web pages into the trio of HTML, CSS, and Javascript. In the past years we’ve managed to mostly move the web to separating style and structure — but what of behavior (Javascript)?

The wrong way

Behaviour has been neglected for a long time and resulted in a sloppy tag-soup similar to this:

<a class="admintools" href="#" onclick="if (confirm('Are you sure you want to delete this comment?')) { new Ajax.Request('/articles/nuke_comment/1694', {asynchronous:true, evalScripts:true, onComplete:function(request){new Effect.Puff('comment-1694',{duration:0.6});}}); }; return false;">nuke</a>

Ouch! That HTML just hurts. This approach works, but has two major faults.

  1. The href attribute has a meaningless value of #, making the raw HTML useless without the Javascript aid. (No degradation whatsoever).
  2. The onclick handler has been set in the HTML, resulting in some pretty knarly source. At first glance, it’s extremely difficult to understand what is happening when you click the link.

The proper way to do things

Widespread use of CSS (along with separation of style and structure) has relieved headaches for developers everywhere. Finally there’s a good solution to all of this that actually makes developing easier. I want to stress this point: using DOM Scripting to add behavior to your documents is easier to develop with..

An Example

So, let’s get started! I’ve put together a small example (view source) of the proper way to embed AJAX calls, while keeping to DRY principles, and separation of structure, style, and behavior. You will not find any extraneous attributes in my source code. First, go ahead and play around with the demo for a bit, deleting blocks and resetting it. You can even disable Javascript and/or CSS and see the results.

View demo
View source of demo

The code powering it

The PHP included is very simple and only there to serve a point. For the most part, the comments explain how it works. The only thing to keep note of is the distinction between AJAX calls (when $_GET['ajax'] exists) and regular calls. The first returns a simple string of text while the second returns a full HTML page.

The HTML

Something to note here is that the HTML contains no inline Javascript. The only thing that lets you know that “Delete Block” will be an AJAX request is the addition of class=”remote”. I’ve used Behaviour to add all Javascript event handlers.

The JavaScript

The beef of the functionality (AJAX-wise) can be found in the Behaviour rules in main.js. Behaviour applies the functionality according to CSS-style selectors. You can read more about Behaviour over at the Behaviour site. I’ve also included the Prototype library and some Scriptaculous effects for UI enhancements.

Let’s have a look at the code that does all the work:

element.onclick = function(){
    if (!confirm('Are you sure you want to delete this?')) return false; 
    // It's always a good idea to give people a second chance to undo a destroying action

    new Ajax.Updater(
        'ajaxmessage', element.href + '&ajax=1',
        {
                asynchronous:true,
                onComplete: function(element){ 
                    Effect.Appear('ajaxmessage') 
                    Effect.Fade('ajaxmessage', {duration:4.0, queue: 'end'});
                }
        }
        ); 
    // Send off the request!

    Effect.DropOut(element.parentNode.parentNode); 
    // This drops out the parent of the parent of the link (the <li> surrounding it)

    return false;
    // This prevents the browser from executing the request
}

When the link with a class of “remote” is clicked, the following actions happen in sequence:

  1. A confirmation box pops up, asking the user to confirm their choice.
  2. A remote request is sent to the file in the href, with an additional parameter of “ajax=1″ appended to the querystring. The results of the remote request are dumped into the innerHTML of the element with an id of “ajaxmessage.”
  3. When the request is completed, the element with an id of “ajaxmessage” is faded in, followed by a slower fade out.
  4. The element containing the link is dropped out to signify to the user it has been removed

Degradation

This example is fully degradable. This means that without Javascript, the entire example will work as expected and still be usable to the end user. Even without Javascript and CSS, the example is still usable. This is a major benefit of using DOM Scripting to add the Javascript event handlers versus the inline approach discussed earlier.

Expanding on the idea

Expanding upon this idea, it is very easy to use Behaviour to control all AJAX actions, even remote form requests! Think about using HTML like this, instead of a whole mess of onsubmit handlers:

<form action="/doit/" method="post" update="update_div_id" class="remote">

Faults of the approach

The approach I have outlined is by no means perfect, but is to serve as example of the good path to choose when starting out with AJAX. With a little bit of creativity, you could easily make the class “remote” apply to all AJAX requests, and even trigger certain effects with some associative arrays.

Now, head on and use AJAX… wisely!

Download the example files: ajax_tamed.zip (25kb)

Enjoy this article? Why not digg it.

17 Comments

comments feed

  1. Gravatar
    Eddy Bones

    February 20 | #

    Nice article! I really don’t know anything about AJAX, and I really wasn’t planning on looking into it, but from what you wrote I can see why it may be a good idea to.

    Might it be possible to put all the files from your example into a zipped folder so readers could play around with it first hand (read: I’m lazy and I don’t want to collect them myself)?

  2. Gravatar
    Kyle

    February 20 | #

    Ask and you shall recieve…

  3. Gravatar
    Eddy Bones

    February 20 | #

    Thanks dude. ;)

  4. Gravatar
    Dave Seah

    February 21st | #

    very cool! like Ed I was thinking I really didn’t want to know anything about AJAX, but your article has convinced me otherwise.

  5. Gravatar
    rabsteen

    February 22nd | #

    goddamnit, kick-ass post.

  6. Gravatar
    Audun

    February 23rd | #

    jQuery is great at this stuff. It doesnt have ajax, but will soon.

  7. Gravatar
    cody lindley

    February 24th | #

    I second the jQuery comment…I think the explanation given here is good but jQuery handles what you are trying to express in a more logical and simplistic fashion.

  8. Gravatar
    Kyle

    February 24th | #

    I fail to see how a library that does not support AJAX can handle AJAX in a more logical fashion. Please do explain.

  9. Gravatar
    cody lindley

    February 25th | #

    Sorry, I really explain myself did I. I was simply implying that JQuery along with prototype or once it supports AJAX is a simpler solution in my opinion then the one you presented here. That is Behaviour + Scriptaculous + Prototype is a great solution, however JQuery once it supports AJAX or along side Prototype is a simpler and more logical solution depending upon a person needs. I?m not trying to take away from what you have written here?its great?I was simply commenting so that you might take a look at JQuery. It?s pretty slick!

  10. Gravatar
    Kyle

    March 8th | #

    Just to revisit this issue: I did take a look at JQuery, and here’s my initial impressions:

    jQuery is using the same methods to apply behaviors as behaviour does – but in my opinion Behaviour does this a lot cleaner than jQuery. Also, it might be of note that Prototype now has support for “cleaner” methods applied to elements, like jQuery does like this:

    $('my_div_id').hide()
    

    As opposed to the “old” Prototype way of:

    Element.hide('my_div_id')
    

    I think this is a massive improvement that stacks Prototype up to par with jQuery in terms of cleanlyness of syntax :) Hopefully we’ll see more like this. Also, not that I have anything against jQuery – it’s just not interesting enough for me to learn in favor of tools I already know.

  11. Gravatar
    BillyG

    April 7th | #

    I just dropped in to let you know that this is the first feed that I have ever had that ran off the right-hand side of my Bloglines window. G/L.

  12. Gravatar
    Andrew Sidwell

    April 13th | #

    Argh! You’re using a GET request to delete something!

  13. Gravatar
    Kyle

    April 13th | #

    Argh! You?re using a GET request to delete something!

    Yeah, this is ultra-sensitive data too. If it gets deleted, the whole internet might shut down.

    Programming is about rationality, not blindly following directions :)

  14. Gravatar
    foti

    December 8th | #

    where get ?

    about

    Beat a hasty retreate

  15. Gravatar
    zack

    January 12th | #

    wow this is great! thanks so much for your work and explanation… i can’t wait to update my skills with your advice.

    blessings…

  16. [...] read more | digg story [...]

  17. Gravatar
    premiere bank

    December 11th | #

    Hello! I’ve browsed all the net and cannot find a website that gives business credit with no personal guarantor. I was at

    best tranfer cradit card life of

Make a Comment

don’t be afraid, it’s just text

Comments are parsed with Markdown. Basic HTML is also allowed.