Encode object literal as url query string in Javascript

I am trying to get rid of a jQuery dependency in a project. One thing the project does is send data to the server like this:

var data = {"apple": [{"kiwi": "orange"}, {"banana": "lemon"}], "pear": "passion fruit"};
$.post( url, data);

      

Thanks to you may not need jQuery , I know how to rewrite $.post

in pure Javascript using XMLHttpRequest

:

var request = new XMLHttpRequest();
request.open( 'POST', url, true);
request.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.send( data);

      

Unfortunately, this description seems to assume that the object is data

already a URL-encoded query string, which is clearly not the case with the example above. It turns out jQuery does more than this: with a given object, the data

above call will $.post

first convert it to a query string that looks like this:

apple%5B0%5D%5Bkiwi%5D=orange&apple%5B1%5D%5Bbanana%5D=lemon&pear=passion+fruit

      

The code snippet using XMLHttpRequest

does not do this and thus the server will throw errors to me.

jQuery also has a wonderful method $.param

that does exactly this transformation. The above code snippet using XMLHttpRequest

will work wonderfully if in the last line I do

request.send( $.param(data));

      

But then I didn't get rid of the jQuery dependency. So I'm looking for a pure Javascript equivalent $.param

. Does anyone have something like this?

Note: The question Plain Javascript equivalent to jQuery.param () asks a similar question, but the accepted answer only works in very simple cases. Applying the function mentioned in this answer to my above data

object gives:

apple=%5Bobject%20Object%5D%2C%5Bobject%20Object%5D&pear=passion%20fruit

      

... which is obviously different from the above result $.param(data)

and loses information as it doesn't recursively.

+3


source to share


3 answers


I made a quick function for you that should achieve this for you, it will create parameters from your key => value pairs and build your non primitive values.

var objToParams = function(obj){
    var paramString = '';
    for (var key in data) {
        var value = obj[key];
        if(obj[key] instanceof Array || obj[key] instanceof Object){
            value = encodeURIComponent(JSON.stringify(value));
        }
        if (paramString != "") paramString += "&";
        paramString += key + "=" + encodeURIComponent(value);
    }
    return paramString;
}

var data = {"apple": [{"kiwi": "orange"}, {"banana": "lemon"}], "pear": "passion fruit"};
console.log(objToParams(data));

      

http://jsfiddle.net/7buy3rjy/



Edit, from your comment, this should work and now matches the $ .param output:

http://jsfiddle.net/mg511z7w/

var data = {"apple": [{"kiwi": "orange"}, {"banana": "lemon"}], "pear": "passion fruit"};

var stringifyParam = function(data, topLevel, keyProp) {
        var string = '';
        for (var key in data) {
            if(keyProp && topLevel[keyProp] ) {
                if ( (topLevel[keyProp] instanceof Array&&topLevel[keyProp].indexOf(data[key])!==0) ) {
                    string += keyProp;
                } else if ( (topLevel[keyProp] instanceof Object&&topLevel[keyProp][key]) ) {
                    string += keyProp;
                }
            }
            if (typeof(topLevel[key])=='undefined') {
                string += '[' + key + ']';
            }
            if (data[key] instanceof Array) {
                string += stringifyParam(data[key], topLevel, key);
            } else if(data[key] instanceof Object){
                string += stringifyParam(data[key], topLevel, key);            
            } else {
                if (typeof(topLevel[key])!='undefined') {
                    string += key;
                }
                string += '=' + data[key];
                string += '&';
            }
        }
        return string;
    },
    toParam = function(data){
        var string = stringifyParam(data,data);
        return encodeURI(string.substring(0,string.length-1).split(' ').join('+'));
    };

console.log(toParam(data)); //apple%5B0%5D%5Bkiwi%5D=orange&apple%5B1%5D%5Bbanana%5D=lemon&pear=passion+fruit
console.log($.param(data)); //apple%5B0%5D%5Bkiwi%5D=orange&apple%5B1%5D%5Bbanana%5D=lemon&pear=passion+fruit

      

+4


source


You can use recursive code, but why not try a simple JSON schema, so it was created - for easier communication between client and server.

Just do it

request.send(JSON.stringify(data));

      



JSON.stringify

accepts an object, which will then be converted to valid JSON, which can be parsed on the server side.

To read more about JSON, there could be no better way than to go through the excerpt tag here

0


source


you can use URIComponent encoding and decoding functions to accomplish this.

Edit

what about this:

var qs = Object.keys(obj).reduce(function(a,k){
    a.push(k+'='+encodeURIComponent(JSON.stringify(obj[k])));
    return a;
},[]).join('&');

// "apple=%5B%7B%22kiwi%22%3A%22orange%22%7D%2C%7B%22banana%22%3A%22lemon%22%7D%5D&pear=%22passion%20fruit%22"

      

instead of this:

var obj = {"apple": [{"kiwi": "orange"}, {"banana": "lemon"}], "pear": "passion fruit"};

var data = encodeURIComponent(JSON.stringify(obj));

// "%7B%22apple%22%3A%5B%7B%22kiwi%22%3A%22orange%22%7D%2C%7B%22banana%22%3A%22lemon%22%7D%5D%2C%22pear%22%3A%22passion%20fruit%22%7D"

var obj2 = JSON.parse(decodeURIComponent(data));

// {"apple":[{"kiwi":"orange"},{"banana":"lemon"}],"pear":"passion fruit"}

      

0


source







All Articles