Post Archive
› January 3, 2006
The Perfectionist's Guide to Building a Query String
Below is a little JavaScript utility I wrote while home with the flu over the holidays (yay immune system!). I have found it to be useful and thought I would pass it along. All it does is return a string in a format suitable for the query portion of a URL for a given form element. You will find this kind of functionality in just about any AJAX code library, but this one is infused with my own brand of anal-retentive attention to detail. I wanted to recreate, as close as possible, the way in which a browser constructs a query string when a form is submitted. I found that the rules for building the name/value pairs for the various kinds of form inputs were not immediately obvious.
Here is the script:
function toQueryComponent(input) {
if (!input.name || input.disabled)
return "";
var n = urlencode(input.name);
switch (input.type) {
case "text":
case "password":
case "submit":
case "hidden":
return n + "=" + urlencode(input.value);
case "textarea":
// normalize line breaks as CR LF pairs as per RFC 1866
var v = input.value.split(/\r\n|\r|\n/).join("\r\n");
return n + "=" + urlencode(v);
case "checkbox":
case "radio":
if (!input.checked)
return "";
var v = getRealValue(input);
if (v === null) v = "on";
return n + "=" + urlencode(v);
case "select-one":
case "select-multiple":
var nvp = [];
var opt, i = 0;
while ((opt = input.options[i++]) != null) {
if (opt.selected) {
var v = getRealValue(opt);
if (v === null) v = opt.text;
// older versions of IE do not support Array.push
nvp[nvp.length] = n + "=" + urlencode(v);
}
}
return nvp.join("&");
default:
// input types reset, button, image, and file not implemented
return "";
}
}
function urlencode(str) {
var v;
try { v = encodeURIComponent(str); } catch (e) { v = escape(str); }
return v.replace(/%20/g,"+");
}
function getRealValue(input) {
var attr = input.getAttributeNode("value");
return (attr && attr.specified) ? input.getAttribute("value") : null;
}
The script is fairly self-explanitory, but a few items are worth noting.
- All input types become translated as
name=valueexcept for multi-select fields, which can have multiple name/value pairs delimited by ampersands. - While browsers may differ on the character(s) they use to represent line breaks in textarea fields, the HTML standard calls for them to be sent as carriage return/line feed pairs (ASCII 13 10).
- If certain input types do not have an explicit
valueattribute, some default value is sent. For radio buttons and check boxes, this value is "on". For select fields, it is the display text. - Since the empty string (
"") is a valid value for an input, it is important to pass this value to the query string instead of using any default, if it is specified. However, testinginput.valuecannot differentiate between an input with no value attribute and one withvalue="". ThegetRealValueutility function returns null if thevalueattribute dot not exist, which informs the script to use the default. - The way the browser encodes unicode characters differs from the result I get from the urlencode function. I am not sure why.
Comments
1. January 3, 2006 03:37 PM
2. January 4, 2006 11:03 AM
3. January 10, 2006 03:05 PM
4. May 12, 2006 05:24 PM
Kamens Posted…
Thanks for this useful tool! I believe there may be one change to be made. IE's treatment of String.split is different than Firefox, etc. For instance, if you run
"511115".split(/1/);
on Firefox, you'll get an array w/ 5 separate elements, whereas in IE you'll get an array w/ 2 elements (b/c IE does not generate empty-string elements between all the matching 1's).
This means that the line:
var v = input.value.split(/\r\n|\r|\n/).join("\r\n");
will result in lost newlines in IE if you have a textarea and insert multiple consecutive newlines (since the join statement won't have as many elements to join on as FF does).
A suggested fix is:
var v = input.value.replace(/(\r\n)|\r|\n/g, "\r\n");
Which doesn't suffer from the IE/FF .split difference.
Dave Posted…
I suppose I should give an example of how to use this to build an entire query string:
function buildQueryString(form) { var str = ""; var element, i = 0; while ((element = form.elements[i++]) != null) { var qc = toQueryComponent(element); if (qc != "") str += "&" + qc; } return str.substring(1); } var form = document.getElementById("someform"); var query = buildQueryString(form); // append query to some URL and GET via XMLHttpRequest, etc.