« Re-Enabling Comments | Home | Restoring the Style and Class Support Eliminated by WordPress MU 1.2.3 »

Better AJAX Form Processing

By Greg | July 18, 2007

Have you found a solid AJAX form processor that actually works? I looked through dozens lately while setting up a newsletter subscription form, and every last chunk of sample code I could find had some fatal flaw (either hidden or immediately obvious) that stopped it from working properly with my form. Here is my own version, which seems to get the job done more robustly.

Every piece of sample AJAX form processing code I tried recently said “tested and found to work with the following form elements: blah blah blah”. I have no reason to doubt the authors when they say they tested the code, but the fact is that I couldn’t find a single example of AJAX form processing code that actually worked with my specific form. The trouble is that you’re not always in control of the form itself — sure, it’s easy enough to get just about any code working if you have full control over every last piece of the form, but what if someone else is producing the form code? How about if they’re not doing a very standards-inspired job of it? And what if it changes over time?

Case in point: the subscription form created by mailing list management software like phplist. (Nothing in the sample code below is specific to phplist, by the way; this is just how I’ve used it.) Yes, the software is finicky and quirky and, at times, thoroughly irritating. But it’s also one of the best alternatives available to stodgy-but-stable Mailman, and it comes out of the box with RSS integration that’s only available after extensive tweaks with Mailman. The phplist package also yields some fairly substandard HTML output, including on its subscription form. The usual workaround is just to write your own subscription form, using what phplist produces as the initial guide. But what if you don’t want to maintain a whole separate subscription form, updating it every time you modify the questions you ask your subscribers or otherwise alter the logical flow of subscribing? What if you want to manage the subscription experience at the level of the phplist administrator interface, rather than at the level of (X)HTML code tweaking? As it happens, if you want to write your own custom form with phplist, you have to do both of these tasks anyway — first make the changes in the administrator interface, then rewrite your custom form code.

I don’t know about you, but I have better things to do with my life. I’d rather write one AJAX routine that will just dynamically grab the subscription form directly from phplist, display it how I want it, and handle the submission and subscription confirmation screen itself. (Again, substitute anything you like for ‘phplist’: this is just the context where I’ve used the code, but you could use it for AJAX processing of any form you like.) My problem, though, was that not one single piece of example code I could find during hours of reading and scrounging the web actually did the job with the clunky phplist subscription form. Sometimes it seemed to work, but I’d discover later that not all the variables actually made it through the XMLHttpRequest and into phplist: something was getting sent, but not everything. Other times, it was immediately obvious that the form contents weren’t being passed correctly, and I’d be dumped out of my spiffy AJAX form processing window and back into the phplist subscription form as phplist presents it.

So anyway, here it is, the result of some hours of fiddling and testing and retesting and nudging and squeezing and occasionally cursing, the code that will run through your form (passed in as thisform) and yield the string which you can POST to phplist or whatever piece of software you happen to be talking to (passed out as formdata):


var formdata = '';
for (i = 0; i < thisform.elements.length; i++) { // loop through all the form elements
  formElem = thisform.elements[i];
  switch (formElem.type) {
    case 'text':
    case 'hidden':
    case 'password':
    case 'textarea':
      formdata += formElem.name + "=" + escape(formElem.value) + '&';
      break;
    case 'checkbox':
    case 'radio':
      if (formElem.checked===true) {
      formdata += formElem.name + "=" + formElem.value + '&';
      } // end of checked box or selected radio button
      break;
    case 'select-one':
      formdata += formElem.name + "=" + escape(formElem.options[formElem.selectedIndex].value) + '&';
      break; // it is possible to do this more succinctly, but then it does not work with older browsers
    default:
      formdata += formElem.name + "=" + escape(formElem.value) + '&'; // setting a default is all-important
  } // end switch
} // end for loop
formdata = formdata.substr(0,(formdata.length -1)); // snip off extra ampersand at the end of the string

Note that for some applications, it may be preferable to encode form values with something more robust than escape(), such as encodeURIComponent(), since the former does not encode the ‘+’ character.

Assuming you’ve already set up your XMLHttpRequest, all that remains is to make the connection, set the headers, and send off the formdata. (Example code for actually doing the XMLHttpRequest is a dime a dozen on the web, with very few differences between them — the main difference being the approach to hand-holding for Microsoft’s problem child of a browser.)

Bookmark and Share:

3 Responses to “Better AJAX Form Processing”

  1. Dewd Says:
    August 6th, 2008 at 7:16 pm

    Awesome… I’ve also looked at a lot of loops to do this, and this is the first correct, working example I’ve seen. Saves me lots of typing, thanks very much.

  2. Greg Says:
    August 7th, 2008 at 11:14 am

    I’m glad it’s been helpful!

    All the best,
    Greg

  3. shahadat Says:
    October 28th, 2008 at 11:05 am

    really its nice solution. i use clsjsphp for process ajax. its tiny and cute. but my copy didn’t handle post. i do a lot of experiment but didn’t success due to process form data. but now it tested and its working fine. actually i missed elements.type method at my script. anyway just here for thanks such nice solutions.

Comments