Getting Started with Ajax

A List Apart is pleased to present the following excerpt from Chapter 27 of Web Design in a Nutshell (O’Reilly Media, Inc., third edition, February 21, 2006). —Ed.

Article Continues Below

The start of 2005 saw the rise of a relatively new technology, dubbed “Ajax” by Jesse James Garrett of Adaptive Path. Ajax stands for Asynchronous JavaScript and XML. In a nutshell, it is the use of the nonstandard XMLHttpRequest() object to communicate with server-side scripts. It can send as well as receive information in a variety of formats, including XML, HTML, and even text files. Ajax’s most appealing characteristic, however, is its “asynchronous” nature, which means it can do all of this without having to refresh the page. This allows you to update portions of a page based upon user events and provides one of the cornerstones of Rich Internet Applications (RIA) referred to in discussions of “Web 2.0.”

The DOM plays into Ajax in a number of ways. How you use the DOM depends a good deal on how you handle the content returned from the server. You can treat the con­tent as simple text using the responseText property of the server response, or you can treat it as XML using responseXML. Assuming the content you pull back from the server is an (X)HTML snippet and you’ve gotten it as responseText, you could drop that content into a particular spot on the page using innerHTML. On the flip side, if the content you pull back is XML and you’ve gotten it as responseXML, you can traverse its DOM, cherry-picking or performing functions on the elements, attributes, and text nodes.

This probably sounds very confusing, but it is pretty easy once we go over a few simple examples. For these examples, we are using the XHConn library for simplifying our interaction with XMLHttpRequest(). The XHConn library is freely available at xkr.us/code/javascript/XHConn/ and allows simple access to XMLHttpRequest() by creating a new XHConn object and then initiating its connect() method as you will soon see.

As with the DOM Scripting examples (above), for a blow-by-blow of what the script is doing, read the JavaScript comments.

Example 1: Ajax with innerHTML#section2

For a simple innerHTML-based Ajax example, we’ll create a quasi-functional address book application. We’ll start with the XHTML page (line wraps marked » —Ed.):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" »
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html  »
  xml:lang="en" lang="en">
<head>
  <title>Ajax Address Book</title>
  <meta http-equiv="content-type" c »
    charset=iso-8859-1" />
    <meta http-equiv="Content-Language" c />
  <script type="text/javascript" src="XHConn.js"></script>
  <script type="text/javascript" src="addressBook.js"></script>
</head>
<body>
  <h1>Simple Ajax Address Book</h1>
  <form acti method="POST">
    <fieldset>
      <legend>Please Choose a Person</legend>
      <select id="person" name="person">
        <option value="">Choose Someone</option>
        <option value="1">Bob Smith</option>
        <option value="2">Janet Jones</option>
      </select>
      <input type="submit" id="submit" name="submit" »
        value="Get the Address" />
    </fieldset>
  </form>
  <pre id="address"></pre>
</body>
</html>

As you can see, we have a simple form with a select, from which to choose a person. Again, we are providing a fallback action for the form, in case our JavaScript cannot run. Below the form, we have a simple pre element that will be displaying the address information from the database.

And now for the JavaScript. Basically, we will be commandeering the select and using its onchange event handler to trigger an XMLHttpRequest() call to obtain the address information for the selected individual. The server will be returning this information as a string like this:

Bob Smith
123 School Street
Anytown, NY 12345

We will take this return as a string and dump it into the pre element using innerHTML. Take a look at the code (line wraps marked » —Ed.):

var addressBook = {
  myConn:      false, // the XMLHttpRequest
  body:        false, // the body element
  target:      false, // the target container
  loader:      false, // the loader
  init:        function(controlId, sbmtBtnId, targetId){
    /* init() takes three arguments:
       * the id of the controller (select)
       * the id of the submit button
       * the id of the target container */
    // test for methods & elements
    if(!document.getElementById ||
       !document.getElementsByTagName ||
       !document.getElementById(controlId) ||
       !document.getElementById(sbmtBtnId)  ||
       !document.getElementById(targetId)) return;
    // set and test XHConn, quitting silently if it fails
    addressBook.myConn = new XHConn();
    if(!addressBook.myConn) return;
    // get the body
    addressBook.body = document.getElementsByTagName('body')[0];
    // get the controller
    var control = document.getElementById(controlId);
    // get the submit button
    var sbmtBtn = document.getElementById(sbmtBtnId);
    // remove the submit button
    sbmtBtn.parentNode.removeChild(sbmtBtn);
    // get the target
    addressBook.target = document.getElementById(targetId);
    // add the onchange event to the controller,
    addressBook.addEvent(control,
                         'change',
                         function(){
                           if(this.value != ''){
                             /* if there's a value,
                                trigger getAddress */
                             addressBook.getAddress(this.value);
                           } else { 
                             // otherwise empty the target
                             addressBook.target.innerHTML = '';
                           }
                         });
  },
  getAddress:  function(id){ // the Ajax call
    // let's let the user know something is happening (see below)
    addressBook.buildLoader();
    /* this is the function that is run
       once the Ajax call completes */
    var fnWhenDone = function(oXML) {
      // get rid of the loader
      addressBook.killLoader();
      // insert the returned address information into the target
      addressBook.target.innerHTML = oXML.responseText;
    };
    // use XHConn's connect method
    addressBook.myConn.connect('index.php', 'POST',
                               'id='+id, fnWhenDone);
  },
  buildLoader: function(){     // builds a loader
    // create a new div
    addressBook.loader = document.createElement('div');
    // give it some style
    addressBook.loader.style.position   = 'absolute';
    addressBook.loader.style.top        = '50%';
    addressBook.loader.style.left       = '50%';
    addressBook.loader.style.width      = '300px';
    addressBook.loader.style.lineHeight = '100px';
    addressBook.loader.style.margin     = '-50px 0 0 - 150px';
    addressBook.loader.style.textAlign  = 'center';
    addressBook.loader.style.border     = '1px solid #870108';
    addressBook.loader.style.background = '#fff';
    // give it some text
    addressBook.loader.appendChild( »
      document.createTextNode( »
        'Loading Data, please waitu2026'));
    // append it to the body
    addressBook.body.appendChild(addressBook.loader);
  },
  killLoader:  function(){     // kills the loader
    // remove the loader form the body
    addressBook.body.removeChild(addressBook.loader);
  },
  addEvent: function(obj, type, fn){  // the add event function
    if (obj.addEventListener) »
      obj.addEventListener(type, fn, false);
    else if (obj.attachEvent) {
      obj["e"+type+fn] = fn;
      obj[type+fn] = function() {
        obj["e"+type+fn](window.event);
      };
      obj.attachEvent("on"+type, obj[type+fn]);
    }
  }
};
/* run the init() method on page load, passing it
   the required arguments */
addressBook.addEvent(window, 'load',
                     function(){
                       addressBook.init('person',
                                        'submit',
                                        'address');
                     });

See this script in action.

Example 2: Ajax with Nodes#section3

Let’s alter the example, and instead of returning a string from the server, this time, make it XML:

<file>
  <name>
    <first>Bob</first>
    <last>Smith</last>
  </name>
  <address>
    <street>123 School Street</street>
    <city>Anytown</city>
    <state>NY</state>
    <zip>12345</zip>
  </address>
</file>

The XHTML page remains the same, but we need to make some minor adjustments to the JavaScript. To highlight the differences, I will touch on each change individually.

The first change, to the onchange event handler of the select, is pretty simple (line wraps marked » —Ed.):

"¦
    addressBook.addEvent(addressBook.control,
                         'change',
                         function(){
                            if(this.value != ''){
                              addressBook.getAddress(this.value);
                           } else {
                             addressBook.target.removeChild( »
                               addressBook.target.firstChild);
                           }
                         });
"¦

Instead of setting the content of the target to empty using innerHTML, the DOM is removing the node that is the target’s first child.

Next up is the getAddress() method (line wraps marked » —Ed.):

"¦
  getAddress:  function(id){
    addressBook.buildLoader();
    var fnWhenDone = function(oXML) {
      addressBook.killLoader();
      if(addressBook.target.hasChildNodes()){
        addressBook.target.removeChild( »
          addressBook.target.firstChild);
      }
      xml = oXML.responseXML;
      var name    = addressBook.getNodeValue(xml, 'first')+' '+
                    addressBook.getNodeValue(xml, 'last');
      var address = addressBook.getNodeValue(xml, 'street');
      var csz     = addressBook.getNodeValue(xml, 'city')+', '+
                    addressBook.getNodeValue(xml, 'state')+' '+
                    addressBook.getNodeValue(xml, 'zip');
      var txt = document.createTextNode(name + " n" +
                                        address + "n" + csz);
      addressBook.target.appendChild(txt);
    };
    addressBook.myConn.connect('getAddress.php', 'POST',
                               'id=' + id, fnWhenDone);
  },
"¦

As we are working with XML, we can use the responseXML property to get the return from the server as a node tree. Then we can traverse that tree, collecting the tidbits of information we need. In this example, we added a new method (getNodeValue()) that makes working with XML returns easier:

"¦
  getNodeValue: function(tree, el){
    return tree.getElementsByTagName(el)[0].firstChild.nodeValue;
  },
"¦

This method takes two arguments: the node tree (tree) and the element (el) whose content is wanted. It returns the nodeValue of the firstChild of the first el within tree or, in other words, the text value of the node requested from the node tree.

Once we have collected all of the requested contents from the XML, the text string is rebuilt and generated with the DOM before being appended to the target. The end result can be seen here.

You may be wondering, why do both examples do the exact same thing? It shows how you can work with two completely different backend systems and still get the results you want. In Ajax, as in many things, flexibility is important to get the job done.

Want to read more?#section4

Web Design in a Nutshell, by Jennifer Niederst Robbins and featuring contributions from Derek Featherstone and Aaron Gustafson, has been completely rewritten to reflect the best practices of the web standards world and is on shelves now.

Ajax resources#section5

For more information on Ajax, consult:

36 Reader Comments

  1. While I’m sure many people will love this article and use it for the Greater Good, I do feel uncomfortable reading anything regarding AJAX (except for the soccer club) where the author doesn’t explain that it is not meant to replace websites and large web applications.

    Surely some of you visit Digg.com once every minute, and you may have noticed the overabundance of AJAX-related posts on that site. Some “cewl thingz” we’ve seen so far: An entire forum made up in AJAX and an entire weblog made up in AJAX. Cool huh? Think again: your back button doesn’t work, you have to click a text link instead. You can’t bookmark anything, no more “hey mom click this link for the latest news on IE7”.

    People need to stop writing articles on how to use AJAX, people should start writing about how to NOT use AJAX.

  2. Once again, I think Gmail provides the clearest example of Ajax Done Right. The back button breaks most of the time, except when it’s most critical—going back from a message to the inbox.

    One really terrific way to learn the ways of the Ajax, in my opinion, is through working with the Google Maps API. It exposes a cross-browser Ajax object, plus it provides a cross-browser facility for crunching xslt. So even if innerHTML is fine in your book, you can do the “right thing” and transform raw data into a table node, and then attach it to your existing page. All without any hassle.

  3. Hageman, if I had a nickel for every article, forum post, blog post, and website that waved the specter of Ajax usability woes in front of my face, the federal mints would have to start making more nickels. Fact is, every time someone so much as *mentions* the word Ajax, you can be guaranteed at least ten warnings like yours (keep an eye on this thread, for example).

    Fact is, you’re always going to have people mucking up usability, and you’re always going to have people who care a great deal about usability. Some of the folks doing the “kewl stuff” are just hacks, but some of them are pioneers. You can’t make an omelette without breaking a few ova after all. I, for one, am happy to see an article that actually deals with a nuts and bolts problem rather than harping on usablilty once again.

  4. Doesn’t this break the accessibility model? Isn’t that going to be the whole problem with AJAX is that it breaks all the rules of accessibility?

  5. It was definitely a good excerpt from the book… however, I think the point has already been brought up that with the ‘craze’ that people have jumped on with Ajax, it is a safe idea to always include a way to make the code unobtrusive. The example, just by itself, entirely breaks without Javascript enabled and if someone is (as was mentioned by CoMags Founder) using a library for the scripts, they may be doing it for speed and convenience, not for accessibility. Granted, if you are making something grand-scale (ala Gmail), maybe (debateable) you can afford to require Javascript with no alternative way to get the content – but most sites don’t fit that mold.

  6. >has been completely rewritten to reflect the best practices of the web standards world and is on shelves now

    Not in the UK yet, unfortunately. But a great book, and I’m sure this edition will be worth getting.

  7. After staring at the same Valentine’s posts for seemingly an age, I was so excited to see an article on AJAX arrive. Always one to expand my knowledgebase this would be a good point to look into a new technology.

    Then within 3 lines I read “nonstandard XMLHttpRequest()” and it’s put me off. IMHO with the drive of recent years to move towards standards and accessibility, to have the very core of this wonderful (new) technology based on a nonstandard device seems to be self-defeating. And with the references to breaking accessibility and the use of innerHTML (isn’t that IE only?) I really don’t think I’m going to bother now. This is really screaming “quick let’s use every fudge we can to make it work on every browser”, which is a mentality which annoyed me in ’97 when it was all the rage, and I really hate it now.

    I’ll keep my eyes open and come back to it in a few versions time when AJAX has matured and Microsoft stop pi**ing about and make IE work.

    Unless somebody can convince me otherwise?

  8. I subscribe to Dean’s view: AJAX is very often an accessibility-killer. One should use it cautious.

  9. @Ross Clutterbuck: You shouldn’t allow yourself to be put off by the word “nonstandard” in this context. There was a time when HTML was nonstandard, for the simple reason that the standard hadn’t been written yet. Work is currently in progress to create the standard defining the behaviour of XMLHttpRequest, and it will reflect the behaviour of the technology as it now exists. And it’s not really fair to knock Internet Explorer in this context, as it was the first browser to offer this capability. (It’s fair to knock it in every other context, though… until IE7 arrives.)

    XMLHttpRequest works across the major browsers, and the code necessary to account for IE less than 7 is a simple if….else… which is easily isolated to a function a few lines long. All existing Ajax libraries that I am aware of have already abstracted away this implementation detail for you.

    The work people are doing with Ajax bears no comparison with the way we were forced to work in 1997. Although the use of innerHTML isn’t something I personally would encourage, it is supported cross-browser, even though it’s not part of any standard. If, like me, you prefer to steer clear of it, there are plenty of places where you can learn standards-based DOM scripting techniques and use them instead. (Note that the innerHTML/DOM debate has nothing to do with Ajax.)

    I’ve been using the techniques now known as Ajax since 2000, but they were restricted to intranet projects because they were supported by IE only. The fact that the other browsers have caught up is the indication that Ajax _has_ matured. It’s time to start using it – when appropriate, and with proper fallback behaviour and accessibility options. A bunch of script kiddies making broken “cool” things just because they can is no reason for a professional to dismiss a valuable toolset in its entirety.

  10. I enjoyed this article. The trouble is that it felt like only half the story. What’s happening on the server? What sort of script is parsing the XML? What sort of XML? Is it raw XML or are you retrieving data from a database? I’d love a follow-up article detailing that part of the story. Unfortunately, as it is, I can’t do very much with the AJAX tips you provided. But it was a very good start.

  11. AJAX and accessibility – two words you seldom hear together, and when you do it’s either to dismiss it (“hey, this is a web *application*”) or it skirts around the point with a hand-waving reference to “making it work without javascript”

    But there’s more to it than that. More complex and more subtle problems arise with devices which *do* support javascript, but which may still not be able to interact with the script. Browser-based screenreaders are among such devices, and for them, progressive enhancement doesn’t work – they are script capable browsers, but their ability to deal with JS is nothing like par with the browser used on its own.

    Have a look at some of the information we collected at Access Matters for evidence of this – http://www.access-matters.com/index/index-of-javascript-tests/

    What we need more of (and I have something in the pipeline to this effect) is articles that stress:

    1 – AJAX is not a suitable replacement for traditional POST/response functionality. It should not be used as such, but only for situations where there is no other way to acheive the same functionality.

    2 – AJAX applications, as far as has been established so far, cannot be made accessible to screenreaders, and so – *any* AJAX application must make a noscript alternative available *as an explicit advance option* – not relying on progressive enhancement or the dinosaur script/noscript parardigm – the choice must be offered to users, upfront.

  12. I to can not wait for the follow up to this story I have always been a fan and passionate aboutlearning AJAX and plan on making all my site using it. A really great read!

  13. Like some others, I was pretty frustrated with the fact that most of the article was not showing me how to make AJAX work, so I figured out the basics of what was missing.

    I think it’s fine that the data store is not mentioned; this is not a tutorial on how to use a database (or whatever). I used a quickie mySQL database, and interacted with it using PHP. To make it work, you have to make a PHP script which echos (literally, using that keyword) any data to be sent back to the AJAX. That handles all the database connection and everything else. If you’re smart, you might make it execute some PHP which isn’t web-accessible, as it will contain your database password. Anyway.

    Keep his directory structure (for now): have the XHConn.js, your custom addressbook.js, your PHP page and your other PHP script(s) all in the same directory. Set up your page the same way he does, with the same names on the Submit button and so forth. You need to change this line:
    addressBook.myConn.connect(‘index.php’, ‘POST’, ‘id=’+id, fnWhenDone);
    The index.php must be changed to reflect the name of the PHP script which echos back the data.

    Apart from that, that’s about it. It should work from there (at least with the string version; I haven’t yet delved into the XML stuff). To have a look at some code, check out http://www.robertgrant.org/addressbookdemo – it doesn’t work, because I’m not going to let you see my password, but you can easily adapt it, I’m sure. Database layout can be inferred reasonably simply, as can my average mySQL+PHP abilities.

    If you want a more step-by-step article, take a look at my website; there’s an article on AJAX there. (If advertising this is a problem mods, please delete this paragraph. Sorry if it is, but I thought it might be helpful!)

  14. I think all of us here would love to be able to design and develop with pure accessibility in mind plus be able to use ‘kewl’ features. But often this is not possible (especially in the real world). I do think however that we can be a little lapse on accessibility where it is acceptable to introduce features that would improve the user’s experiance as long as it is done so the user has a choice.
    What does annoy me is the blantant over use of Ajax where it is not required or could of been better implemented. But that is not a good reason to say ‘never’ but to take it upon ourselves to ensure we provide the knowledge for it to be use right. There is never to many tutorials especailly good ones. I for one enjoyed this tutorial even though I have spent the last few weeks reading everything i can find in books and on the internet about the subject.

  15. hi how do i get the data into my ajax example, xml or sql database? how do i do it with this demo?
    Gparty

  16. Complete websites in Flash drive me around the bend for obvious reasons. Standards, usability, accessibilty. But when flash is used sparingly and cleverly it can be an amazing edition to a website. Is it not the same with AJAX?

    Why on earth would you rely on this technology 100% for your web app when it could be used to enhance site features developed in tandem with other approaches rather than being the silver bullet.

  17. I hope that the browser is required to send a browserID

    if (browserID.name & browserID.verson) = IE.8.1
    render(ASCII)
    else
    render(HTML,CSS)

    Just messing with you head, that would be just too easy

  18. Is it just me or are there others who believe this script has no accessibility issues whatsoever?

    After all, the HTML document contains a regular HTML form with a regular POST going to a page containing the looked-up address.
    Users with accessibility issues (the blind or in any other way limited, this includes search engines) visiting this page will get that good’old FORM with a regular post and no accessibility issues here.
    It’s only the browsers that have javascript enabled that would have all of this AJAX-code executed (Aaron checks for this from line 12 of his example).
    Allright there’s the “back-button” thing. But that’s why this is “getting started” and not “how to perfect”.
    And allright the “second page” (after the post of the regular form) ain’t here. But that’s an obvious thing, right?

    As long as developers create their application the old way first (get, post, regular scripts aso) and only then improve the site with ajax techniques, there’s no problem.

    Concerning the nonstandard XMLHttpRequest, I raised an eyebrow here too. It reminded me it’s nonstandard. I’m hoping the WaSP and others fight for us to get this as a strong and documented standard in every webbrowser to come SOON! I’m scared of investing my time in a technique that has not been adopted by every browser developer and thus might be replaced with something else/better, though I do believe AJAX is worth the investment.

    Aaron, thanks for the article. Excellent work. Nice meeting you too.

  19. bq. After all, the HTML document contains a regular HTML form with a regular POST going to a page containing the looked-up address. Users with accessibility issues (the blind or in any other way limited, this includes search engines) visiting this page will get that good’old FORM with a regular post and no accessibility issues here. It’s only the browsers that have javascript enabled that would have all of this AJAX-code executed (Aaron checks for this from line 12 of his example). Allright there’s the “back-button”? thing. But that’s why this is “getting started”? and not “how to perfect”?.

    Funny, that’s just what I was about to say.

    As for your request about standardization of XMLHttpRequest(), I think we’ll be seeing that in the _very_ near future.

    And it was a pleasure meeting you as well. Hopefully we’ll meet again one day… maybe even in Belgium 😉

  20. After all this discussion of separating presentation from content, it’s disheartening to see so many styles set in the behavior:

    // give it some style
    addressBook.loader.style.position = ‘absolute’;
    addressBook.loader.style.top = ‘50%’;
    addressBook.loader.style.left = ‘50%’;
    addressBook.loader.style.width = ‘300px’;
    addressBook.loader.style.lineHeight = ‘100px’;
    addressBook.loader.style.margin = ‘-50px 0 0 – 150px’;
    addressBook.loader.style.textAlign = ‘center’;
    addressBook.loader.style.border = ‘1px solid #870108’;
    addressBook.loader.style.background = ‘#fff’;

    Wouldn’t it be an improvement to assign a class or id through the JavaScript instead, and move the style rules to the style sheet?

  21. Sitting here at Microsoft Mix 06 and saw a great presentation about the Atlas platform. If you are interested in AJAX development, you should take a look at this. http://atlas.asp.net

    Dale

  22. I still have to duck deeper in Ajax but for now it looks very good. The possibility’s seem to become endless for building webpages nowadays. 🙂

  23. In response to “Janette”:http://www.alistapart.com/comments/gettingstartedwithajax?page=3#23, I go back and forth about seperation of script from presentation. In some cases, it makes sense to set only classes in a script and in others it makes sense to actually apply style via script. I think it is something that needs evaluation on a case-by-case basis. In the case of the “loading” notification you mention, I didn’t see the purpose of adding those minor styles to a seperate style sheet (which would complicate an example on a completely different topic). Were I dealing with a lot of scripted elements which needed style (as in the case of some projects I am working on now), I would actually have a special ria.css file — RIA standing for Rich Internet Application — which is added to the document _by the JavaScript_. In other words, the script carries its styles with it and those styles are only applied if the script actually runs, thereby seperating the styles for the website in question from the script-specific styles and making overall CSS- and JavaScript-management easier.

  24. Thanks, Aaron. This article was exactly the thing I needed to be “getting started with Ajax”. I use some generic scripts to list x records from a table, with next/prev page links at the bottom, and I’ve been wanting to have it update only the data table, and not the entire page. After reading this article, I was able to do just that.

    The big thing for me, though is the fact that this article is a perfect example of what Jeremy calls HIJAX: the page still works without javascript, but WITH javascript, it allows for a “Web 2.0” application.

    OK, on to accessibility issues with ajax. For people using screen readers who also have javascript turned on, when the document itself changes like this due to ajax, the screen reader isn’t aware of it. One solution would be to give screen reader users a link to disable the ajax effect, essentially turning the web app into a Web 1.0 app for them.

    Wouldn’t it be nice if there were a Browser Object Model (BOM) we could interrogate to find out if a screen reader is in use? With this, we could automatically disable the ajax effect, leaving the user in Web 1.0 mode. This BOM could even let us know which plugin was (or would be) loaded to handle a particular mime type, etc. I’m sure there are other things the BOM could do for us, but these two issues came to my mind first.

  25. Great tutorial, hey man and other followers, I have a site that is giving forum based classes on PHP, MySQL, Linux, Apache, JavaScript and most importantly AJAX.

    I would love to have you guys come check it out learn, and actually give some of your lessons and tutorials on the forum for others to learn and read about it, feel free to use your blog address as a sig when you post new lessons or questions and comments.

    I just put up my first lesson, in creating a Shout Box in AJAX so come check it out.

    Grim1208
    LAMP Geekz

  26. The innerHTML method isn’t a part of the DOM specification, but it’s available in Mozilla, IE and Opera. I know for the first two from experience, and the Opera website says it’s supported.

  27. I can read XHTML/CSS with no problem. I can read PHP with some effort. For some reason, JavaScript and AJAX are just so dense, that no matter how I try, my eyes start to blur over!

    I would love to learn the technology, but man, it seems so dense!

  28. Before reading this article, I just heard of this name AJAX, but know nothing about it.

    Aafter reading, understand a little and maybe will like this new tech.

  29. So far I am not convinced to introduce Ajax in my web application. Great web sites are about accessibilty and functionaly – not fancy extra features

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

I am a creative.

A List Apart founder and web design OG Zeldman ponders the moments of inspiration, the hours of plodding, and the ultimate mystery at the heart of a creative career.
Career