5

building upon the $.fn.serializeObject() function from this question, i'd like to be able to support "dot notation" in my form names, like so:

<form>
    <input name="Property.Items[0].Text" value="item 1" />
    <input name="Property.Items[0].Value" value="1" />
    <input name="Property.Items[1].Text" value="item 2" />
    <input name="Property.Items[1].Value" value="2" />
</form>

given that $('form').serializeArray() produces the following:

[{"name":"Property.Items[0].Text","value":"item 1"},
 {"name":"Property.Items[0].Value","value":"1"},
 {"name":"Property.Items[1].Text","value":"item 2"},
 {"name":"Property.Items[1].Value","value":"2"}]

how could i achieve the desired result below:

{Property: {Items: [{Text: 'item 1', Value: '1'},
                    {Text: 'item 2', Value: '2'}]} }

any help would be appreciated.

EDIT: to be specific, the desired code would be added to the serializeObject extension so that in addition to the way it works now, it would also support the above convention. here's the existing method for convenience.

$.fn.serializeObject = function() {
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name]) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};

EDIT 2: feeding off the answer provided, here's my current implementation:

$.fn.serializeObject = function() {
  var o = {};
  var a = this.serializeArray();
  var regArray = /^([^\[\]]+)\[(\d+)\]$/;

  $.each(a, function(i) {
      var name = this.name;
      var value = this.value;

      // let's also allow for "dot notation" in the input names
      var props = name.split('.');
      var position = o;
      while (props.length) {
          var key = props.shift();
          var matches;
          if (matches = regArray.exec(key)) {
              var p = matches[1];
              var n = matches[2];
              if (!position[p]) position[p] = [];
              if (!position[p][n]) position[p][n] = {};
              position = position[p][n];
          } else {
              if (!props.length) {
                  if (!position[key]) position[key] = value || '';
                  else if (position[key]) {
                      if (!position[key].push) position[key] = [position[key]];
                      position[key].push(value || '');
                  }
              } else {
                  if (!position[key]) position[key] = {};
                  position = position[key];
              }
          }
      }
  });
  return o;
};

you can see it in action here

Community
  • 1
  • 1
Omer Bokhari
  • 57,458
  • 12
  • 44
  • 58
  • Nice, 2 things. There's no need to use $.each here it's just overhead. A regular for-loop will do it. 2. Don't declare `var` in a loop (for, while). In Javascript re-assigning a var is way faster then declare a new `var` each time. So set you `var` outside the loops. – fredrik Dec 09 '10 at 13:29
  • @Omer, what does your /^([^\[\]]+)\[(\d+)\]$/ expression check exactly? – R4nc1d Oct 17 '17 at 12:16

1 Answers1

4

This solution is a bit static. But it should do the trick:

var serialized = $.fn.serializeObject(),
            properties = {},
            property = [],
            position = {},
            key = '',
            n = 0,
            matchName = '',
            i = 0;

        for (i = 0; i < serialized.length; i += 1) {
            property = serialized[i].name.split('.');
            position = properties;
            while (property.length) {
                key = property.shift();
                if (key.match(/\[\d+\]/) && key.match(/\[\d+\]/).join().match(/\d+/g) ) {
                    matchName = key.match(/\w+/)[0]
                    n = parseInt(key.match(/\[\d+\]/).join().match(/\d+/g), 10);
                    if (!position[matchName]) {
                        position[matchName] = [];
                    }

                    if (!position[matchName][n]) {
                        position[matchName][n] = {}
                    }

                    position = position[matchName][n]
                } else {
                    if (!property.length) {
                        position[key] = serialized[i].value
                    } else {
                        if (!position[key]) {
                            position[key] = {};
                        }
                        position = position[key]
                    }
                }

            }
        }

        console.log(properties);
fredrik
  • 17,537
  • 9
  • 51
  • 71