Cᴏʀʏ
Cᴏʀʏ

Reputation: 107536

How can I convert query string or JSON object map to single JSON object with jQuery?

For this example, assume that I have a list of months in a form, each with a checkbox next to them. I'm looking for help on doing either of two things:

  1. Convert a query string (e.g. "January=on&March=on&September=on") or
  2. Convert an object map: [{ January: 'on' },{ March: 'on' },{ September: 'on' }]

to a single JSON object: { January: 'on', March: 'on', September: 'on' }

I realize that the first map is already JSON, but instead of the object array I'd like it to be a single JSON object. I can build the map with $('form').serializeArray(); and I can build the query string with $('form').serialize();.

The implementation of .serialize() in the jQuery API is simply:

serialize: function() {
    return jQuery.param(this.serializeArray());
},

which is why I could handle either the first or second answer.

The reason I'd like to do this is because I'm switching from PrototypeJS to jQuery, and in PrototypeJS this was as simple as:

Object.toJSON(Form.serializeElements($('myform'), true));

So, does anybody know of a JSON plug-in (I'd like to stick with ONLY jQuery) that could do this easily, or know of a simple method to achieve the result I'm looking for? Thanks!

Upvotes: 3

Views: 21430

Answers (5)

Alex
Alex

Reputation: 741

You can also use the parseQuery plugin to create an object from the serialized elements.

var contact = $.parseQuery($("#step1 *").serialize());

Upvotes: 0

Rahen Rangan
Rahen Rangan

Reputation: 715

You can try this

String.prototype.QueryStringToJSON = function () {
href = this;
qStr = href.replace(/(.*?\?)/, '');
qArr = qStr.split('&');
stack = {};
for (var i in qArr) {
    var a = qArr[i].split('=');
    var name = a[0],
        value = isNaN(a[1]) ? a[1] : parseFloat(a[1]);
    if (name.match(/(.*?)\[(.*?)]/)) {
        name = RegExp.$1;
        name2 = RegExp.$2;
        //alert(RegExp.$2)
        if (name2) {
            if (!(name in stack)) {
                stack[name] = {};
            }
            stack[name][name2] = value;
        } else {
            if (!(name in stack)) {
                stack[name] = [];
            }
            stack[name].push(value);
        }
    } else {
        stack[name] = value;
    }
}
return stack;
}

Query String

    href="j.html?name=nayan&age=29&salary=20000&interest[]=php&interest[]=jquery&interest[1]=python&interest[2]=Csharp&fan[friend]=rangan&fan[family]=sujan&sports[1]=cricket&sports[2]=football";

usage

alert(href.QueryStringToJSON().toSource())

output

({name:"nayan", age:29, salary:20000, interest:["php", "python", "Csharp"], fan:{friend:"rangan", family:"sujan"}, sports:{1:"cricket", 2:"football"}})

Upvotes: 10

Jeoff Wilks
Jeoff Wilks

Reputation: 363

I know you're trying to turn a query-string into a JSON object, but perhaps you might be interested in going directly from an html form to a JSON object (without having to specify really convoluted name attributes). If so, check out JSONForms: http://code.google.com/p/jsonf/

Disclaimer: I started the jsonforms project. It's still young, but personally I think it rocks!

Upvotes: 0

Cᴏʀʏ
Cᴏʀʏ

Reputation: 107536

kgiannakakis's suggestion to traverse the map was a good starting point, though I don't feel that it qualifies as an answer to my original question. After a couple of hours of head banging, I settled for this, which allows you to serialize elements based on a custom attribute (I didn't want to settle for having to use the 'name' attribute on my form elements, which jQuery requires). I have also started using the JSON library from json.org in order to stringify the object I create. The serializeToJSON function of my plugin is what I was looking for as an answer to my question, the rest is just exta.

Note: This is for a client, so the 'CustomXXX' names and attributes were substituted in for what they actually are

jQuery.fn.extend({
    serializeCustomPropertyArray: function() {
        return this.map(function() {
            return this.elements ? jQuery.makeArray(this.elements) : this;
        }).filter(function() {
            return jQuery(this).attr('CustomAttribute') &&
                (this.checked || /select|textarea/i.test(this.nodeName) ||
                        /text|hidden|password|search/i.test(this.type));
        }).map(function(i, elem) {
            var val = jQuery(this).val();
            return val == null ? null : jQuery.isArray(val) ?
                jQuery.map(val, function(val, i) {
                    return { name: jQuery(elem).attr('CustomAttribute'), value: val };
                }) : { name: jQuery(elem).attr('CustomAttribute'), value: val };
        }).get();
    },
    serializeToJSON: function() {
        var objectMap = this.serializeCustomPropertyArray();
        var objectJson = new Object;
        jQuery.each(objectMap, function() {
            objectJson[this.name] = (this.value !== null) ? this.value : 'null';
        });
        return JSON.stringify(objectJson);
    }
});

This can be called like:

$('#fields').find(':input[CustomGroup="Months"]').serializeToJSON();

Assuming your document looks something like:

<div id="fields">
   <input type="checkbox" CustomGroup="Months" CustomAttribute="January" />January<br />
   <input type="checkbox" CustomGroup="Months" CustomAttribute="February" />February<br />
   ...
</div>

The JSON that's built looks like:

{ January: 'on', February: 'on', ... }

Upvotes: 4

kgiannakakis
kgiannakakis

Reputation: 104178

You can traverse an object map using the $.each utility function.

$(function() {
    map = [{ January: 'on' },{ March: 'on' },{ September: 'on' }];
    $.each(map, function() {
       $.each(this, function(key, val) {alert(key + " = " + val);});;
    });
});

The first each gets you all array objects. With the second one you can get the key and value of your object.

Upvotes: 0

Related Questions