Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JQuery - Serialize form data to Associated Array [closed]

How do you serialise HTML form data to an Associated Array as opposed to the numeric index format produced by $.serializeArray() using jQuery?

The output given by jQuery.serializeArray makes it difficult to directly select values using a numeric index key, Slight index shifts can occur when check boxes are used in form input..

Output of serializeArray

[
  0: [name: 'field-1', value: 'val1'],
  1: [name: 'check', value: 'val2'],
  2: [name: 'check', value: 'val3']
]

Desired Output - More reliable format and simpler value access

[
  'field-1' : 'val1',
  'check' : [ 0 : 'val2', 1 : 'val3' ]
]
like image 876
Marc Avatar asked Oct 28 '13 19:10

Marc


1 Answers

UPDATE 2021

This was a really old problem, Modern JavaScript is far more forgiving these days making the original solution posted obsolete, improvements to JavaScript have also made jQuery quite obsolete.

Since this original post, we have come leaps and bounds, support for serializing Arrays, Objects and even nested combinations of both, to and from JSON in the font/back-end environments is a lot more simple.

Take a look at the following options for submitting complex user input:

Native

Working with JSON

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON

Fetch Example with JSON Request Options

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#supplying_request_options

Axios

Alternative to fetch in native ES6+ JavaScript. Axios will take care of serialization of Arrays and Objects for you.

https://github.com/axios/axios

NodeJS

QueryString - You can import this helper class from NodeJS if supported by your project.

https://nodejs.org/api/querystring.html)


OLD OUT OF DATE CONTENT BELOW

Solution that worked for me was to write my own jQuery functions $.serializeAssoc() and $.serializeObject() alternatives that could also handle multidimensional arrays from multi selection options on forms.

These two functions have their pros and cons; I use serializeAssoc to simplify form data for direct generic value access, typically in JS Validation.

serializeObject has come in handy with multifunction forms using custom numeric key indexes, Simplifying data paring of information submitted from a complicated form set-up of multi-selection fields or forms with values built by DOM where data in a form has parent and child relationships, something serializeAssoc can't handle very well.

serializeAssoc

Following function allows length checks but presents problems with custom numeric key indexes, When submitting the array in an AJAX call it causes index padding

$.fn.serializeAssoc = function() {
  var data = {};
  $.each( this.serializeArray(), function( key, obj ) {
    var a = obj.name.match(/(.*?)\[(.*?)\]/);
    if(a !== null)
    {
      var subName = a[1];
      var subKey = a[2];

      if( !data[subName] ) {
        data[subName] = [ ];
      }

      if (!subKey.length) {
        subKey = data[subName].length;
      }

      if( data[subName][subKey] ) {
        if( $.isArray( data[subName][subKey] ) ) {
          data[subName][subKey].push( obj.value );
        } else {
          data[subName][subKey] = [ ];
          data[subName][subKey].push( obj.value );
        }
      } else {
        data[subName][subKey] = obj.value;
      }
    } else {
      if( data[obj.name] ) {
        if( $.isArray( data[obj.name] ) ) {
          data[obj.name].push( obj.value );
        } else {
          data[obj.name] = [ ];
          data[obj.name].push( obj.value );
        }
      } else {
        data[obj.name] = obj.value;
      }
    }
  });
  return data;
};

serializeObject

Following function below allows custom numeric indexes without causing padding but prevents length check. Check index key counts using an each loop if required. If submitting the object in an AJAX call you must first use JSON.Stringify and pass the value in a var to be decoded server side as direct usage causes an Unexpected end of line error in some browsers.

$.fn.serializeObject = function() {
    var data = {};
    $.each( this.serializeArray(), function( key, obj ) {
        var a = obj.name.match(/(.*?)\[(.*?)\]/);
        if(a !== null)
        {
            var subName = new String(a[1]);
            var subKey = new String(a[2]);
            if( !data[subName] ) {
              data[subName] = { };
              data[subName].length = 0;
            };
            if (!subKey.length) {
                subKey = data[subName].length;
            }
            if( data[subName][subKey] ) {
              if( $.isArray( data[subName][subKey] ) ) {
                data[subName][subKey].push( obj.value );
              } else {
                data[subName][subKey] = { };
                data[subName][subKey].push( obj.value );
              };
            } else {
                data[subName][subKey] = obj.value;
            };
            data[subName].length++;
        } else {
            var keyName = new String(obj.name);
            if( data[keyName] ) {
                if( $.isArray( data[keyName] ) ) {
                    data[keyName].push( obj.value );
                } else {
                    data[keyName] = { };
                    data[keyName].push( obj.value );
                };
            } else {
                data[keyName] = obj.value;
            };
        };
    });
    return data;
};

Usage:

Adding the function

<script>
  (function($){
    $.fn.serializeAssoc = function() {
      ... As Presented Above ...
    };
    $.fn.serializeObject = function() {
      ... As Presented Above ...
    };
  })(jQuery);
</script>

Sample Form

<form id="myForm">
  <input type="text" name="myName" />

  <select name="consoles" multiple>
    <option selected>PC</option>
    <option selected>XBOX 360</option>
    <option selected>PS3</option>
  </select>

  <input type="text" name="sample[100]" value="Mario" />
  <input type="text" name="sample[101]" value="Brothers" />

  <input type="submit" name="submit" value="Submit" />
</form>

Using the function

<script>
  (function($) {
    $('#myForm').submit(function(e){
      e.preventDefault();
      var formData = $('#myForm').serializeAssoc();
      console.log(formData);
    });
  })(jQuery);
</script>

Dynamic form example

<form id="myForm">
  <input type="text" name="myName" value="Spuggy" />

  <div id="characters">
    <input type="text" name="character[]" value="Mario" />
    <input type="text" name="character[]" value="Sonic" />
  </div>

  <div id="consoles">
    <input type="text" name="console[xbox]" value="XBOX One" />
    <input type="text" name="console[playstation]" value="PlayStation 4" />
  </div>

  <input type="submit" name="submit" value="Submit" />
</form>

<script>
  (function($) {
    $('#myForm').submit(function(e){
      e.preventDefault();
      var formData = $('#myForm').serializeAssoc();
      console.log(formData);
    });
  })(jQuery);
</script>

Dynamic form Output

[
  myName: 'Spuggy',
  character: [
    0: 'Mario',
    1: 'Sonic'
  ],
  console: [
    'xbox': 'XBOX One',
    'playstation': 'PlayStation 4'
  ]
]
like image 128
Marc Avatar answered Nov 13 '22 03:11

Marc