JQuery.obj() – Converting inputs to a javascript object

For a while now I’ve been using a JQuery extension that takes selected inputs (and dropdowns and textareas) or inputs contained in the selection and converts them into a javascript object ready for submission with an Ajax post as JSON.

The need for something like this came about when we found that the data that needed to be submitted didn’t neatly fit on a form. An example is where the data was across multiple tabs and the “submit” button needed to be on the first tab.

Now, we have the ability to use the following JQuery:

var newObj = $('#tab1,#tab2,#tab3').obj();

to grab all the inputs into an object, which can then be manipulated before submission. Inputs of type “button” and anything you mark with the class “ignore” won’t be pulled into the object.

The construction of the object is based on the names of the inputs, and follows the dot and bracket notation used in naming .Net MVC, so the following inputs:

<input name="m1.Sub1.Name" value="Anne" />
<input name="m1.Sub1.Age" value="22" />
<input name="m1.Sub1.Numbers[0]" value="1" />
<input name="m1.Sub1.Numbers[1]" value="2" />

will get converted to:

{ m1: { Sub1: { Name: "Anne", Age: "22", Numbers: [ "1", "2" ] } } }

unless of course the “preserveNaming” option is passed in and set to true. In which case the object will be flat, and you’ll get names like “m1.Sub1.Numbers[0]”. Using something like json2, you can stringify this and submit it in an ajax call. It plays very nicely with .Net MVC.

It’s worth pointing out that the JQuery selector can incorporate controls and containers, so you can do something like this:

var newObj = $('#myForm1,#myForm2,#aDropdown').obj({ preserveNaming: true });

and the “newObj” will incorporate all the bits.

So, onto the code, enjoy!:

// Use this jquery extension to convert the inputs, dropdowns & textareas on the selected node(s) into a javascript object
/// options:
///     preserveNaming: default = false - whether the function preserves the names of controls, or splits on .s an []s
(function ($) {

    var _options;

    $.fn.obj = function (options) {

        _options = options || {};

        var obj = {};

        // List of control names that have been seen.
        var namesSeen = [];

        this.each(function (index) {

            var selector = $(this);

            var jqSelector;
            if (selector.is('input') || selector.is('select') || selector.is('textarea')) {
                // This is a control with no inner html
                jqSelector = selector;
            } else {
                //This is a container
                jqSelector = $('input,select,textarea', selector);

            // inputs
            jqSelector.each(function (index) {
                var nodeToCopy = $(this);

                // do not process controls with the ignore class
                // do not process buttons
                if (nodeToCopy.hasClass('ignore') || nodeToCopy.attr('type') == 'button') {

                var name = nodeToCopy.attr('name');
                if (!name || name.length == 0) return; // Don't bother with inputs with no names

                // Only deal with inputs we haven't seen yet
                if (!namesSeen[name]) {

                    var value;

                    if (nodeToCopy.attr('type') == 'checkbox') {
                        if (nodeToCopy.is(':checked')) {
                            value = true;
                        } else {
                            value = false;
                    } else if (nodeToCopy.attr('type') == 'radio') {
                        if (nodeToCopy.is(':checked')) {
                            value = nodeToCopy.val();
                        } else {
                            // pretend we haven't seen un-selected radio buttons so we end up with the selected one
                    } else {
                        value = nodeToCopy.val();

                    namesSeen[name] = true;

                    addValue(obj, name, value);
        }); // each selector

        return obj;

    var addValue = function (obj, name, value) {

        if (_options.preserveNaming) {
            obj[name] = value;
        } else {
            var parts = name.split('.');
            parts.reverse(); // must reverse to use the pop() as we will be going root to leaf.

            add(obj, parts, value); // recursevely add name parts to existing object

    var add = function (curObj, remainingNames, value) {

        var curName = remainingNames.pop();
        if (!curName || curName.length == 0) return; // Don't bother with blank name

        var arrayData = null;

        // see if the name is a list in the form of AAA[NNN]
        var match = new RegExp("(.+)\\[([0-9]*)\\]").exec(curName);
        if ((match !== null) && (match.length == 3)) {
            var arrayData = { arrName: match[1], arrIndex: match[2] };

            // Make the current object and name be the array and the index of the array respectively
            // Equivalent to calling curObj[arrayData.arrName][arrIndex] in the section below
            if (curObj[arrayData.arrName] === undefined) curObj[arrayData.arrName] = [];
            curObj = curObj[arrayData.arrName];
            curName = arrayData.arrIndex;

        if (remainingNames.length == 0) {
            // This is the leaf node
            // If not an array value, just place it on the leaf object.
            curObj[curName] = value;
        } else {
            // Not the leaf, have to extend existing object
            if (curObj[curName] === undefined) curObj[curName] = {};
            add(curObj[curName], remainingNames, value);

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: