views:

3399

answers:

7

Just wondering if there is anything built-in to Javascript that can take a Form and return the query parameters, eg: "var1=value&var2=value2&arr[]=foo&arr[]=bar..."

I've been wondering this for years.

+2  A: 

I'm not entirely certain myself, I recall seeing jQuery did it to an extent, but it doesn't handle hierarchical records at all, let alone in a php friendly way.

One thing I do know for certain, is when building URLs and sticking the product into the dom, don't just use string-glue to do it, or you'll be opening yourself to a handy page breaker.

For instance, certain advertising software in-lines the version string from whatever runs your flash. This is fine when its adobes generic simple string, but however, that's very naive, and blows up in an embarrasing mess for people whom have installed Gnash, as gnash'es version string happens to contain a full blown GPL copyright licences, complete with URLs and <a href> tags. Using this in your string-glue advertiser generator, results in the page blowing open and having imbalanced HTML turning up in the dom.

The moral of the story:

   var foo = document.createElement("elementnamehere"); 
   foo.attribute = allUserSpecifiedDataConsideredDangerousHere; 
   somenode.appendChild(foo);

Not:

   document.write("<elementnamehere attribute=\"" 
        + ilovebrokenwebsites 
        + "\">" 
        + stringdata 
        + "</elementnamehere>");

Google need to learn this trick. I tried to report the problem, they appear not to care.

Kent Fredric
Right on. Document.write is *so* 1995, anyway.
+7  A: 

No, I don't think standard JavaScript has that built in, but Prototype JS has that function (surely most other JS frameworks have too, but I don't know them), they call it serialize.

I can reccomend Prototype JS, it works quite okay. The only drawback I've really noticed it it's size (a few hundred kb) and scope (lots of code for ajax, dom, etc.). Thus if you only want a form serializer it's overkill, and strictly speaking if you only want it's Ajax functionality (wich is mainly what I used it for) it's overkill. Unless you're careful you may find that it does a little too much "magic" (like extending every dom element it touches with Prototype JS functions just to find elements) making it slow on extreme cases.

Stein G. Strindhaug
Just wondering if there's anything built-in. Seems like there should be. I hate prototype, but I'm not holding that against you :)
When JavaScript was designed, Ajax was not yet discovered, therfore parsing a form just to get the querystring (that it would creati itself when submitted) probably did not make much sense. Today it does, tough... Btw, compared to script.aculo.us, prototype is *nice*. :)
Stein G. Strindhaug
+1  A: 

I tried to search for an answer to this question some while ago, but I ended up writing my own function that extracts the values from the form ..

it's not perfect but it fits my needs.

function form_params( form )
{
    var params = new Array()
    var length = form.elements.length
    for( var i = 0; i < length; i++ )
    {
     element = form.elements[i]

     if(element.tagName == 'TEXTAREA' )
     {
      params[element.name] = element.value
     }
     else if( element.tagName == 'INPUT' )
     {
      if( element.type == 'text' || element.type == 'hidden' || element.type == 'password')
      {
       params[element.name] = element.value
      }
      else if( element.type == 'radio' && element.checked )
      {
       if( !element.value )
        params[element.name] = "on"
       else
        params[element.name] = element.value

      }
      else if( element.type == 'checkbox' && element.checked )
      {
       if( !element.value )
        params[element.name] = "on"
       else
        params[element.name] = element.value
      }
     }
    }
    return params;
}

form_params returns a (key -> value) mapping of the parameters. the input is the form element (DOM Element)

It doesn't handle fields that allow multiple selection.

hasen j
I have the same code :D It beats including some giant framework.
+1  A: 

As Stein says, you can use the prototype javascript library from http://www.prototypejs.org. Include the JS and it is very simple then, $('formName').serialize() will return what you want!

Shyam
+3  A: 

If you don't want to use a library, this should cover most/all of the same form element types.

function serialize(form) {
  if (!form || !form.elements) return;

  var serial = [], i, j, first;
  var add = function (name, value) {
    serial.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
  }

  var elems = form.elements;
  for (i = 0; i < elems.length; i += 1, first = false) {
    if (elems[i].name.length > 0) { /* don't include unnamed elements */
      switch (elems[i].type) {
        case 'select-one': first = true;
        case 'select-multiple':
          for (j = 0; j < elems[i].options.length; j += 1)
            if (elems[i].options[j].selected) {
              add(elems[i].name, elems[i].options[j].value);
              if (first) break; /* stop searching for select-one */
            }
          break;
        case 'checkbox':
        case 'radio': if (!elems[i].checked) break; /* else continue */
        default: add(elems[i].name, elems[i].value); break;
      }
    }
  }

  return serial.join('&');
}
Jonathan Lonowski
Thanks! I was just facing the same problem as the original poster, and your function was exactly what I needed.
+1  A: 

For those of us who prefer jQuery, you would use the form plugin: http://plugins.jquery.com/project/form, which contains a formSerialize method.

Cugel
A: 

You don't actually need a form to do this with Prototype. Just use Object.toQueryString function:

Object.toQueryString({ action: 'ship', order_id: 123, fees: ['f1', 'f2'], 'label': 'a demo' })

// -> 'action=ship&order_id=123&fees=f1&fees=f2&label=a%20demo'

cheers!

-- Thibaut

Thibaut Barrère