While working on Particletree’s shopping cart system for our magazine, we decided that we wanted to create a flawless user experience for all users without having to sacrifice the added user interface benefits provided by Ajax goodness. A lot of places will tell you that it is ok to use JavaScript and Ajax as long as it’s not mission critical. Well, we don’t think web apps have to be boring to be reliable.

HTML Form Builder

And so we’ve developed some solid strategies to help us use Ajax in our apps without having to worry if they’re essential or not to the application. After some heavy experimenting, we’ve developed a method for making web pages work regardless of the user’s browser settings. While other sites have implemented their own versions of degradable Ajax, we found the lack of documentation on the subject discouraging. And so it is with great pleasure that we present to you the Particletree method of degradable Ajax.

See It In Action

We cooked up a simple to do list to demonstrate how a simple Ajax application can work with or without JavaScript. Now, don’t be mislead by the simplicity of the demo. The techniques introduced in this tutorial are scalable and can easily allow even more powerful Ajax applications to retain their sweet action without losing their non-J-juice using customers.

The Files

A few notes before you download the code. I am testing a wide range classes and methods in both the JavaScript and the PHP. This may result in some unstable code that is not optimized. In order to see what is happening with degradable Ajax, all you need to look at is ‘processList.php’, ‘todo.js’, and ‘index.php’. I still felt it necessary to zip the entire project—just be cautious with the other files.

How to Approach Degradable Ajax

The general strategy here is to start by creating a page that works like a normal site—processing information on page loads and refreshes. Then, if JavaScript is enabled, we have our scripts bypass this normal functionality and replace it with sweet Ajax functionality.

Now, creating a degradable Ajax site is a bit different from a creating a site with unlimited Ajax potential. Here are some strategies I’ve come up with to help you build a degradable Ajax page.

JavaScript: Start with JavaScript turned off. Doing this forces you to make sure you structure your page to work without JavaScript enabled. This does not mean that you can’t add slick Ajax animations in later, but it does keep you focused on the goal. It also means that we are temporarily removing “onclick” from our toolbox.

Markup: If you design a project with no JavaScript from the start (and therefore no “onclick”), you will realize the only elements that perform an action and are “clickable” places for user interaction are the <a> elements and the <input type="submit"> elements. What you are sacrificing then, is the ability to make divs and other common elements clickable. I have, however, noticed that most of your general web 2.0 effects can be accomplished no problem with just these two elements. It’s sort of like in CSS when you have to make sure an element doesn’t have a fixed width AND left or right padding to insure it doesn’t create problems with browsers that don’t follow the box model properly. It’s not hard, just requires a little extra creative problem solving effort.

Noscript: And let’s not forget that when you’re creating an interface, there’s a W3C ordained element meant specifically for allowing users access to content that wouldn’t be available if a browser has scripting disabled. Let’s read:

The noscript element allows authors to provide alternate content when a script is not executed. The content of a noscript element should only be rendered by a script-aware user agent in the following cases:

  • The user agent is configured not to evaluate scripts.
  • The user agent doesn’t support a scripting language invoked by a script element earlier in the document.
  • The user agent can’t access an external script.

18.1. The noscript element

Noscript is an easy way to provide alternate interfaces to your server side functions. And if you’re using a technology like xsl for your application, it’s as easy as placing an include in your markup.

Server Side: As you are writing your server side functions, keep in mind that you would like for them to be accessed through both Ajax and through post backs. Make your code as modular as possible so that every action can be done with a simple call. Instead of structuring code in a linear fashion:

<?php    if($_REQUEST("action") == "new") {
        // code to add user to database

Try structuring it like this:

    if($_REQUEST("action") == "new") {
    }    function addUser() {
        // code to add user to database

How It Works

Step 1 - Disabling All Actions

Now that you have a functional site that uses no JavaScript or Ajax, the next goal is to find out how to disable that boring functionality if JavaScript is enabled. To do that, we’re going to use a simple unobtrusive JavaScript call to insert an “onclick” line to disable all <a> elements and <input type="submit"> elements. For example, the unobtrusive JavaScript will make a disabled link look like this:

<a href="process.php" onclick="return false">My Link</a>

By returning ‘false’ we are preventing the link from ever activating, so when it is clicked nothing will happen. When applying this to an <input> element, though, apply the return to the <form> tag using onsubmit instead of onclick. Here is what our unobtrusive script looks like that disables all links.

function disableActions () {
    var links = document.getElementsByTagName("a");    for (i=0; i<links.length; i++){
        var link = links[i];
        link.onclick = function() {return false;}

If you want to learn more about this method, I recommend checking out this sample chapter from Dom Scripting by Jeremy Keith. I stumbled across it while writing this tutorial and he does a beautiful job describing degradable JavaScript. Definitely, a good read.

So we are now left with a page that does not function if JavaScript is enabled, but works just fine if JavaScript is disabled. Good - moving on.

Step 2 - Restoring Functionality

I am trying a new and somewhat experimental technique in order to add Ajax functionality back into the links after they have been disabled. Let’s say we have a link in our markup that looks like so:

<a href="processList.php" class="funcDeleteItem">Delete</a>

Notice that the link was intentionally assigned a descriptive className. We’re going to take that className above and make a matching JavaScript function. Because JavaScript has the ability to reference a function as a string using objects, we’re going to leverage that ability here:

var allFuncs = new Object();allFuncs["DeleteItem"] = function() {     // process ajax code here
    return false; 

We have a link and a function, but they aren’t connected in any fashion. Let’s go back to our disableActions() function from above and modify it to create a connection between the link and the function.

function disableActions () {
    var links = document.getElementsByTagName("a");    for (i=0; i<links.length; i++){
        var link= links[i];
        link.onclick = allFuncs[getAction(link.className)];
}function getAction(name) {
    allNames = name.split(" );
    for(x = 0; x >< allNames.length; x++) {
        if(left(allNames[x], 4) == "func") {
            return right(allNames[x], allNames[x].length - 4);
    return "";

Now each link has a unique function attached to it by means of the link’s class. Using our new function we can now send out the appropriate AJAX requests.

Step 3 - Handling Request with the Server

Currently, we have managed to send off an Ajax request and make sure everything works regardless of the JavaScript settings. Now we have to see how the server will handle the different requests. The easiest way to approach this is to modify the query string of the different requests.

<a href="processList.php?action=delete" class="funcDeleteItem">Delete</a>

Do the same thing for the URL in your Ajax call, except flag it as being Ajax.

url = "processList.php?action=delete&ajax=yes";

On processList.php, we can now easily handle the request.

    if(isset($_REQUEST["action"])) {
        switch ($_REQUEST["action"]) {
            case "delete":
                if(isset($_REQUEST["ajax"])) echo "true";
                else Header("location: index.php");

The reason I split it into two different constructs is for handling the return. You may want different return values based on the type of operation you are performing.

Step 4 - Handling The Return

The most difficult aspect of Ajax is how to handle the return. There are toolkits available as well as more advanced techniques using XML and XSL. Since those techniques require a full feature on their own, I have kept the demo in this feature using basic techniques for the sake of simplicity.

If JavaScript is disabled, index.php will load like a normal web page would - it loops through the database and displays the results. When Ajax is used, nodes are being appended to either list. In order for this to work, we have to keep track of the id of each item. So each <li> should have access to the id of the current item. When the page first loads, this can be handled in the php:

<li id="L<?php echo $row["itemID] ?>"><p>

The same concept needs to be applied to functional links as well. Once that is done, we can now reference id’s with the JavaScript.

activeID = right(, - 1);

Then I created a global named ‘activeID’, and whenever an Ajax request is made I set the global with the value contained in the <li> or <a> elements. In this example, a link with an id of L14 will set activeID equal to 14. Once we have handles on the unique id’s of nodes, we can now easily manipulate the DOM accordingly.

Is This Necessary?

Since less than 10% of Internet users are estimated to have JavaScript turned off and since it is safe to say that a good portion of those people probably aren’t going to fall into your target market, you should ask yourself: should you even bother making your web applications degradable? Well, it’s not for me to tell you what’s best for your particular situation, but I’ve done some research and I think you should be aware of some of the concerns that are out there.

By not making your applications degradable, you are, ultimately, excluding users from an experience on your site by providing no fall back for when things go wrong on the client side. We’ve already talked about degradable forms on Particletree and so if the general consensus is that you shouldn’t be trusting client side scripting to do all of your form processing, perhaps trusting it to do all your application processing isn’t wise either. This is especially true when you consider that we’re in an era of transition between the old web and the new.

Your decisions on degradable Ajax should depend on two things:

  • Functionality - Do you only power optional features like live search with Ajax? If so, does it harm the user experience if these features “break” without JavaScript? More importantly, does the rest of your site (the required features) work without JavaScript?

  • Cost - What is the cost to develop a degradable Ajax site, and what is the cost of the users you may lose by not doing so? It is hard to measure the intangible costs associated with this, but if you are developing a business application, there will be a more significant loss than if you are developing, say, a personal blog.

Shelly Powers presents us with a bold statement regarding the issues and problems surrounding Ajax:

The end result of all these issues�compatibility, accessibility, and security�is a fundamental rule of web page design: whatever technology you use to build a web page has to degrade gracefully.

The Importance of Degrading Gracefully

In addition to the degradation problems, Dare Obasanjo recently identified a list of current problems that prevent the Ajax from being the best thing you could do for your web application:

The List

  1. How to abstract away browser detection from each page in the application
  2. How to make the site accessible or at least work on non-Javascript enabled browsers
  3. How to efficiently manage the number of connections to the server created by the client given the “chattiness” of AJAX applications compared to traditional web applications
  4. How to reduce the amount of time spent downloading large script files
  5. How to create permalinks to portions of the application
  6. How to preserve or at least simulate the behavior of the browser’s ‘Back’ button

Moving Beyond the Basics: Scott Isaacs on AJAX Design Patterns

A valid counterpoint to all this, however, is that JavaScript and Ajax enhance the user’s experience so greatly; there’s little reason why we shouldn’t require this tool of our users. The more users realize the necessity of these tools, the more they will support them. How are they to realize the necessity of JavaScript if developers don’t boldly say, “You can’t use my app unless you have JavaScript enabled?” For an in depth look at the consequences of forcing JavaScript, though, check out The Man in Blue’s article on JavaScript is not the devil’s plaything.

If you want to read more about successfully using Ajax, then you’ll want to check out Jeremy Keith’s Progressive enhancement with Ajax. He presents some nice ideas on the subject and suggests a strategy of balance that satisfies all users, which is exactly what we tried to accomplish here today.

HTML Form Builder
Ryan Campbell

The Hows and Whys of Degradable Ajax by Ryan Campbell

This entry was posted 5 years ago and was filed under Features.
Comments are currently closed.


  1. Kevin Hale · 5 years ago

    Fantastic article buddy. Now, get some rest.

  2. Ryan Campbell · 5 years ago

    I wanted to add a couple of informal notes for clarification:

    1) The files contain limited error handling. What is nice about this method is that you can return true to disable Ajax – so if an error is caught just return true and it will default to the non javascript functionality.

    2) I wanted to emphasize that the zip file contains a lot of test code. There may be leaks in it. However, the code that looks at degradable Ajax should be good.

    3) I have noticed a weird caching problem in firefox when javascript is turned off. Basically, you click “delete” or another action and the database updates, but the page does not update on refresh. It only seems to happen on some computers, and only on firefox. If you have this problem, or know of a fix, please let me know.

    4) I would really like to make a bulletproof technique that handles a lot of ajax with minimal effort. To make this degradable it only took a couple lines of server code. When I added checkbox onclick functionality, it added much more. So basically, I’m open to suggestions to make crazy functionality easy to implement.

    Thanks for reading.

  3. ellardus · 5 years ago

    Great article,

    I think every serious website should use degradable Ajax/JavaScript, especially for essential functions. You article helps us inderstand and implement,

    Thanks, great work and great site!

  4. Matthew Pennell · 5 years ago

    That’s an interesting way of handling the re-assignment of actions to links (with the className) – although worth pointing out to novices that using the original disableActions() on its own will kill all the links on a page; it must be used in conjunction with the className-to-function code if you only want to replace the functional bits of the application (and not break your main navigation, etc.)

    (off-topic: why am I the only developer in the world using ? It makes styling them so much easier…)

  5. Matthew Pennell · 5 years ago

    Comment form ate my markup :(

    That should be [button type=”submit”] but with the proper angle brackets.

  6. Jeremy Keith · 5 years ago

    Excellent write-up!

    I haven’t looked too closely at the code. As with any powerful technology, the secret to using Ajax well does not lie in memorising syntax or code: instead, it’s a mindset. This article describes that mindset very well.

    Create your application the old-school way using page refreshes and server-side processing—then use JavaScript to intercept and hijack those calls and replace them with calls to the XMLHttpObject instead.

    I like to call it… Hijax. :-)

    Hey, what good is a paradigm if you don’t have a catchy name, right? ;-)

    Some examples of Hijax in action: (shopping cart)

    They were built the old fashioned way first and then enhanced with Ajax afterwards.

  7. Ryan Campbell · 5 years ago

    I used to use button elements but then I ran into a problem with them. And now that I think of it I can’t remember the problem. I’ll have to start using them again to see if they work for me because they are much easier to style.

    And Jeremy – thanks for the links. I had a tough time finding much of anything related to the topic.

  8. Wei · 5 years ago

    Another simple example that can work without JS

    And a quick description of the code required (it does sit behind a framework)

  9. Masklinn · 5 years ago

    Oh god, Jeremy, how the hell did you think of such a nice designation for progressive ajax enhancement?

    That one will be used and abused, if not by others at least by me, I swear.

  10. Ben · 5 years ago

    See Behaviour.js.

  11. Dustin Diaz · 5 years ago

    I noticed you referenced my ajax contact form in your introductory paragraphs. Just give me some time, the documentation is coming right around the corner. You’ve now given me encouragement to speed up the process ;)

  12. Ryan Campbell · 5 years ago

    I’ve been looking forward to your write up. Let us know when it is ready so we can check it out.

  13. Enej · 5 years ago

    Wow, nice write up. My opinion is that if you have the resources/knowledge to build something with ajax (I know its not magic) you should (or at least try to) have the knowledge to make something work even with ajax disabled. Thanks again.

  14. Stewart Vardaman · 5 years ago

    I tried it with Firefox using a third-party JS blocker (AdSubtract Pro), and AdSub stops it from working.

  15. Ryan Campbell · 5 years ago

    Thanks for noticing that. I’ll download that JavaScript blocker and see what I can find. I have also run into caching problems when JavaScript is disabled, so that may be happening to you instead. I’m going to go do some testing. If you can offer me any more details about the specifics of the problem you are noticing I would be grateful.


  16. Patrick Lafleur · 5 years ago

    About the noscript tag it should not be used anymore or in very rare case.

    The way I work is to develop the html path before any scripting. When it is working this way, I add functionalities through scripting.

    Imagine you have a combo box that when selected triggers a page refresh with new data.

    I would implement the “html only” path first. This means I would add a “Refresh” button that must be clicked after selecting an item in the combo box. This works in all browser.

    When everything is working fine, I will implement the scripted path. Instead of wrapping the button with a noscript tag, I will hide the button from the javascript. The idea is to add behavior through scripting.

    This is a trivial case, but imagine a more complex that requires more than one scripted path depending on the browser capabilities (AJAX support, etc). If you use the noscript tag, what would happen if you still needed the button in one of your scripted path? It would not be possible.

    Using the noscript tag also sprinkles your code in the XHTML and the Javascript making it harder to understand/test. If you put all the behavior code in the javascript in the same place, it is much easier to maintain.

  17. Joel Alexandre · 5 years ago

    Does the code work if javascript is enabled but for some reason ajax doesn’t work? ex: activeX disabled in IE.


  18. Ryan Campbell · 5 years ago

    Joel - my demo does not work that way, but enabling it to do so is extremely easy (I just happened to forget).

    You can approach this in two different ways:

    1) Once the first function runs on page load, check for the existence of the object. If the object is not there, don’t attach any events, just exit the function.

    2) When an event fires, a function is run. Once that function is omcplete, it returns false to stop the page from refreshing/processing. Well, what if the JavaScript encountered an error? Simply return true instead of false, and the page will operate as if JavaScript were disabled.

    Hope that helps. Let me know if I’ve overlooked something.

  19. Chris Bloom · 5 years ago

    re: Patrick Lafleur

    If you aren’t going to make use of the noscript tag just make sure that you aren’t hiding the button using only CSS. Just because a browser supports CSS does not mean that Javascript is supported or enabled. Even worse is vice versa: If a user has javascript enabled, but CSS turned off (perhaps to use a personal high-contrast style sheet for acccessability reasons). In this case the noscript tag works better, though it is probably best to remove the element from the DOM all together. I don’t think this scenario would affect using the class name to assign an AJAX function, though…

  20. Chris Bloom · 5 years ago

    PS: I just looked over the demo - I like how the check boxes replace the complete button. Nice touch! However, the form should have a submit button for adding new items. Not really for compatibility, but just for accessibility/usability.

  21. Ryan Campbell · 5 years ago

    I agree with you Chris - I kept the demo as simple as possible given the time frame I had to make it. A submit button was on my list, I just didn’t get around to putting it in.

  22. Adam · 5 years ago


    regarding your 3rd informal note, I have had similar problems in the past with various browsers caching a page instead of refreshing it (after submitting a form or clicking a link etc.)

    I fixed the problem by sending the following headers in my php script to tell the browser never to cache my page ever. apparently some of the headers work in some browsers, others in others, hence the need for 5 of them…

    hope this helps, - Adam

  23. Adam · 5 years ago

    sry, it apparently stripped out the php tags…

    second time’s a charm ;)

    header(“Content-type: text/html”); header(“Expires: Mon, 26 Jul 1997 05:00:00 GMT”); header(“Cache-Control: no-store, no-cache, must-revalidate”); header(“Cache-Control: post-check=0, pre-check=0”, false); header(“Pragma: no-cache”);

  24. Dustin Diaz · 5 years ago

    Ryan, I’m seeing this article in two places… is that correct? I feel lost. Anyway, I did in fact package up something for the contact form only for the reasons that so many folks were asking for it. It isn’t in fact a kit of any kind, it is really just focused on the contact form itself. I would in fact encourage folks to come here and check out your kit as a more useful tool to implement into several other places of their website.

    On the thing about ‘how others have made their own forms of degradable ajax - lack of documention is discouraging’ - don’t worry about any modifications. You could however just write a tip in the next issue (if this webzine makes corrections in “next issues”) to come checkout the release for it with ‘some’ (very beta) documentation. It at least points the developer in the right direction.

    All the best bro, Dustin

  25. Dustin Diaz · 5 years ago

    Quick question. Will this kit work with php 4? I noticed class variables set as private and constructors set with the __construct syntax. I am not entirely too familiar yet with PHP 5’s object model, and I haven’t seen constructors set in that way before. Thoughts?

  26. Ryan Campbell · 5 years ago

    Dustin - we will add your notes to the corrections section of next issue. Also, the reason you see it in two places is because we reproduce the Particletree articles in PDF format now, and they are appended free to the end of every magazine.

    Most of my stuff is in PHP5, so this will not work on a PHP4 setup. This has become a bit of a problem, so I will be writing those tutorial which deal primarily with a server side concept in PHP4. Too many hosts don’t fully support PHP5, and 4 is still the popular release. It is a shame though because 5 has a lot of cool features.

  27. Joe Scalise · 5 years ago

    Am I the only person here that doesn’t like the implementation? Don’t get me wrong, conceptually I’m there with you, but your implementation mixes form and function. It’s important to make sure that you separate out your style from your markup, and your function from your style. You have all of these elements of your application mushed together which makes it difficult to for example, apply CSS to some of your elements because they already have a class attribute for your javascript. People have tried this before with success, and others have tried the very same idea with a different attribute instead of class. However, it is important to keep clear lines on what is form and what is function. The question is, does this save you more time and make your code more readable, or are you going to run into problems when in a maintenance cycle? If your customer came back to you and said, hey, I want all of my delete links to have this special style, are you going to have funcDelete as a class in your CSS?!? what about passing a parameter to your javascript, like an index or sequence number, or a special event handler… are you going to have hidden form fields that you stuff things into for the “current action” the more exceptions you make, the more unstable your code becomes. I prefer when I have to do this kind of thing to use an id attribute, because it is perfectly fine for every element to have a different id attribute, and then have some inline javascript after my elements to bind the function to the user control after the page has loaded. Also, I don’t really like parsing text for what I’m trying to do. It’s feasible that you can assume that when you model your page without ajax the action elements in your markup are easy to distinguish and therefore you should be able to bind the functions to them in a similar manner. This is one reason I prefer strict XHTML. However, like you said in the statement about Cost, most of these coding standards are irrelevant if you are simply designing a person blog and not a business application.

  28. Ryan Campbell · 5 years ago

    Joe - I considered each of the options you mentioned, but chose className for the following reasons:

    1) Every html element can have more than one className, so if I were to write <a></a> there would be no problem.

    2) I originally did this with the ID of the element, but ran into a big problem. When you create something that loops, such as a table or list, each element requires a unique ID. So in my list of 10 items, what if I want each element to fade out onclick. That would require 10 javascript function, one to match each ID. Doing this with className only requires 1 function for all list elements.

    3) The other two methods to accomplish this are to hard code a hidden form field, like you suggested, or to hard code rules into your JavaScript. To me, neither of those are ideal. I would rather have a slight cross over of form and function. The idea of hard coding something doesn’t sit well with me.

    4) When working with a designer, I can give a list of function names and what they do, such as funcDelete, funcAppear. They dont have to know how or why something works, it just does if they add the className. However, if I hard coded the actions they would not be able to change them without my help.

    Thanks for the feedback though. I really would like to develop this into a stable, reliable solution.

  29. Daro Bruno · 5 years ago

    Your tag line has a misuse of a the word insure;

    With some unobtrusive JavaScript, structured server side code, and smart markup, Ryan shows you how to insure your fancy Ajax applications works with or without JavaScript.

    This sentence should read;

    With some unobtrusive JavaScript, structured server side code, and smart markup, Ryan shows you how to ensure your fancy Ajax applications work with or without JavaScript.

  30. Dallas Pool · 5 years ago

    To get rid of the FF Cache problem append a random string in your get requests… somthing in the line of…


    ugly, but simple and it works….

    it will force the browser to see the linked page as new content…

  31. Dallas Pool · 5 years ago

    should be link.php?var1=varVal&random= *PHP md5(microtime()); *endPHP

  32. Robert Nyman · 5 years ago


    It took me 1 hour and 40 minutes to get home from work today. First the subway was late, then the train was immensely late. After that I had to ride my bike for 15 minutes in the pouring rain, and also dropping my cell phone on the way.

    But none of this made me mad, and do you know why? Because I read a printed version of this article on the train and then used my PDA to read comments on it, and it made me very happy.

    Great article, well-written and interesting!

    I only have two minor and humble opinions about the JavaScript code. First:

    for (i=0; iRyan,

    It took me 1 hour and 40 minutes to get home from work today. First the subway was late, then the train was immensely late. After that I had to ride my bike for 15 minutes in the pouring rain, and also dropping my cell phone on the way.

    But none of this made me mad, and do you know why? Because I read a printed version of this article on the train and then used my PDA to read comments on it, and it made me very happy.

    Great article, well-written and interesting!

    I only have two minor and humble opinions about the JavaScript code. First:

    for (i=0; i

  33. Robert Nyman · 5 years ago

    Oh my, the code really got butchered. One more try here:

    for (i=0; i<links.length; i++){ var link = links[i]; link.onclick = function() {return false;} }

    The variable really shouldn’t be declared for every increment in the above loop. It should rather be:

    var link; for (i=0; i<links.length; i++){ link = links[i]; link.onclick = function() {return false;} }

    Second, I was taught not to have return statements scattered in the function, but to have just one at the end, so I guess this function:

    function getAction(name) { allNames = name.split(" ); for(x = 0; x >< allNames.length; x++) { if(left(allNames[x], 4) == "func") { return right(allNames[x], allNames[x].length - 4); } } return ""; }

    should look like this:

    function getAction(name) { var strReturn = ""; allNames = name.split(" ); for(x = 0; x >< allNames.length; x++) { if(left(allNames[x], 4) == "func") { strReturn = right(allNames[x], allNames[x].length - 4); break; } } return ""; }

  34. Brendan · 5 years ago

    Warning: mysql_connect() [function.mysql-connect]: Access denied for user ‘particle_web’@’’ (using password: YES) in /home/httpd/vhosts/ on line 93

    Thought I’d let you know…

  35. Ryan Campbell · 5 years ago


    I’m glad to hear that the article made your day better in some way. Your feedback is absolutely correct, so thank you for pointing that out. You will usually see me keep up with the bad habit of scattered returns. I’ll have to try and break out of that eventually.

    Brendan - thanks for the heads up. We are moving hosts, so I will fix it soon.

  36. rps · 5 years ago

    Regarding the importance of working for non-js-enabled browsers, I’m new at this web development thing, but I’ve already run into several bugs relating to manipulating a document with Javascript in Firefox (try cloning a node and calling “for(x in node) { print(x + node[x])}” in a pre-Deer Park Firefox, for example).

    I’m a lone developer and I don’t get to send my code to a QA team every day where every conceivable code path would be tested with every conceivable browser. So I figure that, even if I’m willing to exclude people who turn Javascript off (and I am), it still had better damned well work without Javascript because I don’t trust the browser and I don’t know when and where it’s going to fail.

    I’d like to hear whether this is a problem in practice or not from people who’ve been at it for more than 2 weeks.

  37. Azad · 5 years ago

    Is it important to make it degradable? I dont think so. Who on earth is still using NN4 or IE 5 ?

    Its time we move on and put a “This site uses Javascript” message somewhere in the page.

    I dont want some poor schmuck who’s using NN4 / IE5 to visit my website. I refuse to work my ass off just so that those people can view a page. Let them reallize that its time to upgrade their browser.

  38. migrosch · 5 years ago

    Great article and great writing and work, you’ve been doing both on this site and on the Treehouse magazine.

    @Azad: I think it is very important to make it degradable. Just keep in mind that there are people out there who don’t use regular browsers because of some kind of disability. Therefore by “not working your ass off [for] some poor schmuck” you are being ignorant to those users and show them your nicest “keep off” smile. I don’t believe that this is AAA (acceptable accessibility attitude). But that’s just my two Euro cents.

  39. prabu · 5 years ago

    Everyone needs a hug.

  40. ranvier · 5 years ago

    Like prabu said, “Everyone needs a hug!” :)

  41. Daniele Florio · 5 years ago

    What do you think of this? Is a form that use AHAH in GET or POST..


    Sorry but is in italian language :)

    bye Daniele

  42. Neil M. · 5 years ago

    Great article on what has always been an important issue with javascript in the past and is even more important now.

    For those who hesitate to use degradable ajax because they believe that the non-JS population is too small, there is a solid reason to use it with modern browsers in any case. When confronted with a list of links, I prefer to open them in tabs with Firefox. I do not know how it is implemented in Opera or in IE 7, but if a page is opened in a new tab (or a new window) Firefox does not run the onclick handler or any javascript in the link. If not implemented properly, AJAX would easily fail to function the way the user intends.

    Again, another small audience to consider, but the number of small audiences accumulates…


  43. etng · 5 years ago

    good code,and good idea. I learned much from your article ,3x

  44. Daniele Florio · 5 years ago

    Hi, I have developed a first example of Degradable LiveSearch in AHAH that works with and without enabled javascript.



  45. eddmun · 5 years ago

    Ah hah! Yes thank you so much!!

    I have been looking for a way to disable the normal form action for ages!


  46. Brian · 5 years ago

    This is a really well written article. Got here from the WeBreakThings blog. Thanks.

  47. Mortimer · 5 years ago

    Hey, I really liked this article! the ?ajax=yes parameter is a great idea and I was looking for someone to confirm that ;)

    Your article made me think a lot and I then came with an object oriented idea to the degradation problems of parameters, code reusability etc…

    What do you think of it? do you think it is a viable approach to behaviour separation? It is my first attempt to do something like that in js, experts advice would be great.

    Cheers for making my neurons move forward ;)

  48. Ryan Campbell · 5 years ago

    Mortimer - That looks like an interesting approach. I am always a fan of making things object oriented and easier to understand/reuse. If you’re comfortable with his syntax and structure, then give it a shot.

  49. Pedram · 5 years ago

    Don’t know if anyone knows this but there is a goof up in some of your examples… like here…

    if($_REQUEST(“action”) == “new”) { // code to add user to database }

    $_REQUEST is a super global array… not a function and since $ cannot precede function calls, you could not make an ancillary function just in case you find this mistake often… like it appears again here…

    if($_REQUEST(“action”) == “new”) { addUser(); }

    I wrote rapid framework to fix a lot of this mess.

  50. Ryan Campbell · 5 years ago

    Thanks for catching that Pedram. They were meant to be [] instead of (), but it slipped by somehow. These days I don’t use $_REQUEST anymore, so it is weird looking back at this :)

  51. Steve · 5 years ago

    Thanks for the article, I think it is very important for web apps to be degradable with so many new mobile users, many of which don’t use javascript enabled browsers.


  52. Sven · 5 years ago

    That’s a great article, Ryan. Thanks!

    One question about the usage of anchors in the demo.

    Don’t you think that this practice could run into massive issues when there’s some kind of “accelerator” installed on the client - fetching all “links” in the background and thus setting done/deleting the todo items while the user’s wondering what to insert next?

    IMHO using GET requests for state changing actions is a big no-no, but probably I’m missing something here.

    Of course, the demo could easily be changed to use inline forms for each action.

  53. zielak · 4 years ago

    Everyone needs a hug.

  54. Naked Teens · 4 years ago

    Hi look my blog Naked Teens

  55. Wallace · 4 years ago

    I liked this site, it’s neat. Good job!

  56. Edwin · 4 years ago

    I really enjoyed this page. I will be linking and I will be trying to read and research all that there is to offer from this site!

  57. Rob Boles · 4 years ago

    I realize this article is a year old, and I don’t have the time to read all comments so forgive me if this is redundant, but … Is there a reason why you opted not to give your anchor tags both an href AND an onclick function while adding a return false? For example: click me It seems to do the trick without having to use any substitution scripts or class/method associating.

  58. Yaroslav · 3 years ago

    Thank you very much for this article. I am planning to start write open source Ajax based ecommerce application, and you advices helped me very much. Thank you for you job.