Convierta datos de formularios a objetos JavaScript con jQuery

¿Cómo convierto todos los elementos de mi formulario en un objeto JavaScript?

Me gustaría tener alguna forma de construir automáticamente un objeto JavaScript desde mi formulario, sin tener que recorrer cada elemento. No quiero una cadena, como lo devuelve $('#formid').serialize();, ni quiero que me devuelva el mapa $('#formid').serializeArray();

preguntado el 26 de julio de 09 a las 10:07

porque el primero devuelve una cadena, exactamente como lo que obtendría si enviara el formulario con un método GET, y el segundo le brinda una matriz de objetos, cada uno con un par de nombre y valor. Quiero que si tengo un campo llamado "correo electrónico", obtenga un objeto que me permita recuperar ese valor con obj.email. Con serializeArray (), tendría que hacer algo como obj [indexOfElement] .value -

@James: la respuesta aceptada utilizando la biblioteca JSON-js de D. Crockford. He aquí un ejemplo: github.com/tleese22/google-app-engine-jappstart/blob/master/src/… -

@Taylor Sí, diría que la respuesta correcta usa la biblioteca de Crockford y la función de Tobias así: JSON.stringify ($ ('myForm'). SerializeObject ()) -

@Jonz: hay otras razones además del envío / transmisión para usar un elemento de formulario. Si está haciendo un trabajo pesado con los valores del formulario dentro de JavaScript (por ejemplo, una aplicación de una sola página), es muy útil tenerlos en un formato de objeto para acceder y manipular. Además, las cadenas de consulta HTTP Post y Get no son los únicos formatos para mover datos. -

30 Respuestas

serializarArray ya hace exactamente eso. Solo necesita masajear los datos en el formato requerido:

function objectifyForm(formArray) {
    //serialize data function
    var returnArray = {};
    for (var i = 0; i < formArray.length; i++){
        returnArray[formArray[i]['name']] = formArray[i]['value'];
    }
    return returnArray;
}

Tenga cuidado con los campos ocultos que tienen el mismo nombre que las entradas reales, ya que se sobrescribirán.

Respondido 19 ago 20, 09:08

como dice tvanfosson, ¿por qué iterar sobre la colección dos veces? - Israel

¿Quiere decir "por qué usar serializeArray para obtener los datos en primer lugar?" Debido a que serializeArray ya está escrito, se prueba unitariamente en varios navegadores y, en teoría, podría mejorarse en versiones posteriores de jQuery. Cuanto menos código escriba que tenga que acceder directamente a elementos inconsistentes como elementos DOM, más estable será su código. - Tobías Cohen

Tenga cuidado, serializeArray () no incluirá elementos deshabilitados. A menudo deshabilito los elementos de entrada que están sincronizados con otros elementos de la página, pero aún quiero que se incluyan en mi objeto serializado. Es mejor que uses algo como $.map( $("#container :input"), function(n, i) { /* n.name and $(n).val() */ } ); si necesita incluir elementos deshabilitados. - samuel meacham

@TobiasCohen No maneja foo[bar]-tipo entradas como se esperaba, sin mencionar la mayoría de las otras variedades de nombres de entrada. Después de sentirme muy frustrado con las soluciones superficiales a este problema, terminé escribiendo mi propio complemento jQuery, los detalles en la respuesta que proporcioné a esta pregunta. - macek

@macek Sé que esto tiene unos meses de antigüedad, pero ¿desde cuándo las matrices usan índices no numéricos? Nadie debería nombrar una entrada foo [bar] y esperar tratarla como una matriz. ¿Estás confundiendo matrices y hashes? Sí, comúnmente se entiende que [] es un descriptor de acceso, pero no solo para matrices. También decir que es HTML válido pero no en la especificación HTML es una contradicción. Sí, es posible que el navegador no se ahogue, pero no muchos servidores web sabrán cómo deserializar eso como lo harían con una matriz. ¿Por qué? Porque no está en la especificación HTML. Por lo tanto, es de hecho inválido. - kroehre

Convierta formularios a JSON como un jefe


La fuente actual es en GitHub y Cenador.

$ bower instalar jquery-serialize-object


El siguiente código es ahora .

El siguiente código puede funcionar con todo tipo de nombres de entrada; y manipúlelos como esperabas.

Por ejemplo:

<!-- All of these will work! -->
<input name="honey[badger]" value="a">
<input name="wombat[]" value="b">
<input name="hello[panda][]" value="c">
<input name="animals[0][name]" value="d">
<input name="animals[0][breed]" value="e">
<input name="crazy[1][][wonky]" value="f">
<input name="dream[as][vividly][as][you][can]" value="g">
// Output
{
  "honey":{
    "badger":"a"
  },
  "wombat":["b"],
  "hello":{
    "panda":["c"]
  },
  "animals":[
    {
      "name":"d",
      "breed":"e"
    }
  ],
  "crazy":[
    null,
    [
      {"wonky":"f"}
    ]
  ],
  "dream":{
    "as":{
      "vividly":{
        "as":{
          "you":{
            "can":"g"
          }
        }
      }
    }
  }
}

Uso

$('#my-form').serializeObject();

La brujería (JavaScript)

(function($){
    $.fn.serializeObject = function(){

        var self = this,
            json = {},
            push_counters = {},
            patterns = {
                "validate": /^[a-zA-Z][a-zA-Z0-9_]*(?:\[(?:\d*|[a-zA-Z0-9_]+)\])*$/,
                "key":      /[a-zA-Z0-9_]+|(?=\[\])/g,
                "push":     /^$/,
                "fixed":    /^\d+$/,
                "named":    /^[a-zA-Z0-9_]+$/
            };


        this.build = function(base, key, value){
            base[key] = value;
            return base;
        };

        this.push_counter = function(key){
            if(push_counters[key] === undefined){
                push_counters[key] = 0;
            }
            return push_counters[key]++;
        };

        $.each($(this).serializeArray(), function(){

            // Skip invalid keys
            if(!patterns.validate.test(this.name)){
                return;
            }

            var k,
                keys = this.name.match(patterns.key),
                merge = this.value,
                reverse_key = this.name;

            while((k = keys.pop()) !== undefined){

                // Adjust reverse_key
                reverse_key = reverse_key.replace(new RegExp("\\[" + k + "\\]$"), '');

                // Push
                if(k.match(patterns.push)){
                    merge = self.build([], self.push_counter(reverse_key), merge);
                }

                // Fixed
                else if(k.match(patterns.fixed)){
                    merge = self.build([], k, merge);
                }

                // Named
                else if(k.match(patterns.named)){
                    merge = self.build({}, k, merge);
                }
            }

            json = $.extend(true, json, merge);
        });

        return json;
    };
})(jQuery);

respondido 29 nov., 19:18

Entonces, eso funciona bastante bien. Pero tiene un nombre incorrecto: no devuelve JSON, como su nombre lo indica. En cambio, devuelve un objeto literal. Además, es importante verificar hasOwnProperty; de lo contrario, tus arreglos tienen cualquier cosa que esté adjunta a su prototipo, como: {números: ["1", "3", indexOf: function () {...}]} - belleza

@frontendbeauty en realidad, toJSON es exactamente lo que la especificación dice que debería llamarse: developer.mozilla.org/en/JSON#toJSON()_método un nombre poco afortunado. - Ryan Florencia

@Marek, hice una prueba aquí en jsFiddle. El truco consiste en nombrar su selección correctamente. <select name="foo" multiple="multiple"> no funcionará en ningún escenario. Sin embargo, si usa [], como en <select name="bar[]" multiple="multiple">, funcionará bien :) - macek

Quería señalar que github.com/serbanghita/formToObject es un método de JavaScript similar (no se necesitan bibliotecas de terceros) que hace el mismo trabajo. Soporta 'múltiples', ignora elementos 'deshabilitados'. - Șerban Ghiță

Esta solución debería estar en la parte superior, ya que se ocupa del problema de las claves anidadas como nombres de elementos de formulario. - gatocuadrado

Qué hay de malo en:

var data = {};
$(".form-selector").serializeArray().map(function(x){data[x.name] = x.value;}); 

Respondido 22 Jul 13, 10:07

@LayZee: si no se selecciona nada, ¿por qué lo querrías en tu back-end? si debe seleccionar una opción, valide la entrada antes de serializar. - Rafael Herscovici

Si no devuelve nada, ¿por qué no usa .each en lugar de .map ?? - azerafati

Es tan simple porque es súper ingenuo ... no maneja casillas de verificación con el mismo nombre. Cada vez, anulará el elemento marcado antes. Definitivamente necesitará alguna detección de tipo de entrada para asegurarse de que esté correctamente serializado. - Joshua F. Rountree

Si desea una solución jQuery pura, puede usar var form = {}; $.each($(this).serializeArray(), function (i, field) { form[field.name] = field.value || ""; }); - tim-montague

$(this).serializeArray().reduce(function(m,o){ m[o.name] = o.value; return m;}, {}) - sitios

Una versión fija de la solución de Tobias Cohen. Éste maneja correctamente valores falsos como 0 y ''.

jQuery.fn.serializeObject = function() {
  var arrayData, objectData;
  arrayData = this.serializeArray();
  objectData = {};

  $.each(arrayData, function() {
    var value;

    if (this.value != null) {
      value = this.value;
    } else {
      value = '';
    }

    if (objectData[this.name] != null) {
      if (!objectData[this.name].push) {
        objectData[this.name] = [objectData[this.name]];
      }

      objectData[this.name].push(value);
    } else {
      objectData[this.name] = value;
    }
  });

  return objectData;
};

Y una versión de CoffeeScript para su conveniencia de codificación:

jQuery.fn.serializeObject = ->
  arrayData = @serializeArray()
  objectData = {}

  $.each arrayData, ->
    if @value?
      value = @value
    else
      value = ''

    if objectData[@name]?
      unless objectData[@name].push
        objectData[@name] = [objectData[@name]]

      objectData[@name].push value
    else
      objectData[@name] = value

  return objectData

Respondido el 31 de diciembre de 11 a las 19:12

En el coffeescript, ese primer bloque si se puede acortar a value = @value ? '' - nzifnab

Y si está intentando serializar formularios similares a Rails, es posible que desee eliminar la raíz del elemento de las claves generadas. Para lograrlo, agregué un nuevo parámetro keyMap y la siguiente línea: key = if keyMap? then keyMap(@name) else @name. Ahora puede pasar la función de mapeo como (name) -> name.match(/\[([^\]]+)]/)[1]. Y luego habría que cambiar todos los siguientes @name a key, por supuesto - damir zekić

@ DamirZekić, si su elemento raíz fue post, simplemente podrías hacer $('form').serializeObject().post. No es necesario un mapeo sofisticado. - macek

@ DamirZekić ¿Qué está haciendo esta línea? if (!objectData[this.name].push)?? - gatito

@kittu Está comprobando si objectData[this.name] tiene el método push (aproximadamente, es una matriz). Si es una matriz, empuja el valor, si no es una matriz, lo convierte en una matriz para que varios valores con la misma clave se combinen en una matriz. - daniel moore

Me gusta usar Array.prototype.reduce porque es de una sola línea y no se basa en Underscore.js o similar:

$('#formid').serializeArray()
    .reduce(function(a, x) { a[x.name] = x.value; return a; }, {});

Esto es similar a la respuesta que usa Array.prototype.map, pero no necesita desordenar su alcance con una variable de objeto adicional. Uno para de comprar.

NOTA IMPORTANTE: Formularios con entradas que tienen duplicados name Los atributos son HTML válido y, en realidad, es un enfoque común. El uso de cualquiera de las respuestas en este hilo será inapropiado en ese caso (ya que las claves de objeto deben ser únicas).

Respondido 26 Abr '15, 09:04

Esto es bastante elegante. Pero vale la pena señalar que array.prototype.reduce() no está disponible en IE8 ya que forma parte de la especificación ECMAScript 5. Entonces, si necesita compatibilidad con IE8, querrá usar un polyfill u otra solución por completo. - gfullam

Es cierto, pero es bastante fácil de rellenar. Además, el dolor de cabeza de IE8 es casi Terminado, gracias al gran trabajo de Microsoft con IE11 Enterprise Mode, ya no atiendo a usuarios individuales con IE8, pero cuando aparece una organización con 10,000 empleados que usan IE8 ... eso es diferente. Afortunadamente, Microsoft está trabajando duro en ese problema. - ethan marrón

Bueno, debería hacer que su personal de TI busque en el modo IE11 Enterprise: proporciona un navegador moderno Y una forma de ejecutar aplicaciones compatibles con IE8. Movimiento inteligente por parte de Microsoft: howtogeek.com/184634/… - ethan marrón

Todas estas respuestas me parecieron tan exageradas. Hay algo que decir a favor de la simplicidad. Siempre que todas las entradas de su formulario tengan el atributo de nombre establecido, esto debería funcionar solo jim dandy.

$('form.myform').submit(function () {
  var $this = $(this)
    , viewArr = $this.serializeArray()
    , view = {};

  for (var i in viewArr) {
    view[viewArr[i].name] = viewArr[i].value;
  }

  //Do stuff with view object here (e.g. JSON.stringify?)
});

respondido 31 mar '11, 22:03

Sin embargo, no maneja datos de formularios anidados, por eso las respuestas se vuelven más complicadas. - belleza

Funcionó muy bien para mí. Solo necesitaba almacenamiento de pares clave-valor; la secuenciación y luego guardar en localStorage o cookie funcionó a la perfección. - Greg Petit

Realmente no hay forma de hacer esto sin examinar cada uno de los elementos. Lo que realmente desea saber es "¿alguien más ya ha escrito un método que convierte un formulario en un objeto JSON?" Algo como lo siguiente debería funcionar: tenga en cuenta que solo le dará los elementos del formulario que se devolverían a través de un POST (debe tener un nombre). Esto es no probado.

function formToJSON( selector )
{
     var form = {};
     $(selector).find(':input[name]:enabled').each( function() {
         var self = $(this);
         var name = self.attr('name');
         if (form[name]) {
            form[name] = form[name] + ',' + self.val();
         }
         else {
            form[name] = self.val();
         }
     });

     return form;
}

Respondido 26 Jul 09, 15:07

es cierto, me encantaría un complemento que hiciera esto por mí. la limitación de tener un nombre no es gran cosa. ¿Esto extraerá todos los campos de un formulario, incluidas las áreas de texto y selecciones? - Israel

No estoy seguro si quiere dar cuenta de [deshabilitado] pero no creo que deba enviarse / retirarse. - meder omuraliev

podría ser más simple usar serializeArray () para obtener el mapa, y luego usar un código similar al anterior para convertirlo en un objeto JSON normal, de esta manera no estoy tratando con el formulario en sí - Israel

Usar serializedArray funcionaría, pero esencialmente estaría iterando sobre la colección dos veces, una vez para producir la matriz, luego sobre la matriz. No veo la necesidad de eso. - tvanfosson

Ajustaré el selector para habilitado / deshabilitado. - tvanfosson

Si está utilizando Underscore.js puede utilizar el relativamente conciso:

_.object(_.map($('#myform').serializeArray(), _.values))

Respondido 26 Abr '15, 08:04

Verifiqué que hay un problema con todas las otras respuestas, que si el nombre de entrada es como una matriz, como name[key], entonces debería generarse así:

name:{ key : value }


Por ejemplo: Si tiene un formulario HTML similar al siguiente:

<form>
    <input name="name" value="value" >
    <input name="name1[key1]" value="value1" >
    <input name="name2[key2]" value="value2" >
    <input name="name3[key3]" value="value3" >
</form>

Pero debe generarse como el JSON a continuación, y no se convierte en un objeto como el siguiente con todas las demás respuestas. Entonces, si alguien quiere traer algo como el siguiente JSON, pruebe el código JS a continuación.

{
    name  : 'value',
    name1 : { key1 : 'value1' },
    name2 : { key2 : 'value2' },
    name3 : { key2 : 'value2' }
}

$.fn.getForm2obj = function() {
  var _ = {};
  $.map(this.serializeArray(), function(n) {
    const keys = n.name.match(/[a-zA-Z0-9_]+|(?=\[\])/g);
    if (keys.length > 1) {
      let tmp = _;
      pop = keys.pop();
      for (let i = 0; i < keys.length, j = keys[i]; i++) {
        tmp[j] = (!tmp[j] ? (pop == '') ? [] : {} : tmp[j]), tmp = tmp[j];
      }
      if (pop == '') tmp = (!Array.isArray(tmp) ? [] : tmp), tmp.push(n.value);
      else tmp[pop] = n.value;
    } else _[keys.pop()] = n.value;
  });
  return _;
}
console.log($('form').getForm2obj());
$('form input').change(function() {
  console.clear();
  console.log($('form').getForm2obj());
});
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<form>
  <input name="name" value="value">
  <input type="checkbox" name="name1[]" value="1" checked="checked">1
  <input type="checkbox" name="name1[]" value="2">2
  <input type="checkbox" name="name1[]" value="3">3<br>
  <input type="radio" name="gender" value="male" checked="checked">male
  <input type="radio" name="gender" value="female"> female
  <input name="name2[key1]" value="value1">
  <input name="one[another][another_one]" value="value4">
  <input name="name3[1][name]" value="value4">
  <input name="name3[2][name]" value="value4">
  <input name="[]" value="value5">
</form>

contestado el 25 de mayo de 20 a las 18:05

Esta respuesta cubre el caso mencionado, pero no cubre casos como checkbox [] o incluso uno [otro] [otro_uno] - leonardo beal

@LeonardoBeal arreglé mi ans ... ¡mira esto ahora ...! - Bhavik Hirani

Soy el votante en contra y voté en contra porque eval no debe usarse de esta manera porque eval, cuando se usa de esta manera, promueve prácticas terriblemente poco confiables, con errores, de mal desempeño y potencialmente inseguras. - jack giffin

No puedo estar de acuerdo con que esta sea una buena respuesta. Y, por favor, cuando escriba las respuestas, haga que su código sea autoexplicativo o explíquelo. this.c = function(k,v){ eval("c = typeof "+k+";"); if(c == 'undefined') _t.b(k,v);} es breve y no explicativo. Un desarrollador con menos experiencia simplemente copiará esto sin entender por qué y cómo funciona. - iras

@JackGiffin Mira mi nuevo código ahora porque lo eliminé eval() de mi código. - Bhavik Hirani

Ok, sé que esto ya tiene una respuesta muy votada, pero otra se hizo una pregunta similar recientemente, y también me dirigieron a esta pregunta. También me gustaría ofrecer mi solución, porque ofrece una ventaja sobre la solución aceptada: puede incluir elementos de formulario deshabilitados (lo que a veces es importante, dependiendo de cómo funcione su interfaz de usuario)

Aquí está mi respuesta del otra pregunta SO:

Inicialmente, estábamos usando jQuery's serializeArray() método, pero eso no incluye elementos de formulario que están deshabilitados. A menudo deshabilitaremos los elementos de formulario que están "sincronizados" con otras fuentes en la página, pero aún necesitamos incluir los datos en nuestro objeto serializado. Entonces serializeArray() Está fuera. Usamos el :input selector para obtener todos los elementos de entrada (tanto habilitados como deshabilitados) en un contenedor dado, y luego $.map() para crear nuestro objeto.

var inputs = $("#container :input");
var obj = $.map(inputs, function(n, i)
{
    var o = {};
    o[n.name] = $(n).val();
    return o;
});
console.log(obj);

Tenga en cuenta que para que esto funcione, cada una de sus entradas necesitará un name atributo, que será el nombre de la propiedad del objeto resultante.

Eso en realidad está ligeramente modificado de lo que usamos. Necesitábamos crear un objeto que estuviera estructurado como un IDictionary .NET, así que usamos esto: (lo proporciono aquí en caso de que sea útil)

var obj = $.map(inputs, function(n, i)
{
    return { Key: n.name, Value: $(n).val() };
});
console.log(obj);

Me gustan ambas soluciones, porque son usos simples de la $.map() función, y tienes control completo sobre tu selector (entonces, qué elementos terminas incluyendo en tu objeto resultante). Además, no se requiere ningún complemento adicional. Simple y antiguo jQuery.

contestado el 23 de mayo de 17 a las 12:05

Intenté esto en un proyecto, usando map De esta manera, crea una matriz de objetos con una sola propiedad, no contrae todas las propiedades en un solo objeto. - Joshperry

[ACTUALIZACIÓN 2020]

Con un simple delineador en vainilla js que aprovecha desdeEntradas (como siempre, verifique el soporte del navegador):

Object.fromEntries(new FormData(form))

Respondido el 16 de junio de 20 a las 16:06

Esta es una implementación excelente (y la más simple), la única advertencia es que requiere un navegador web bastante actualizado. Por ejemplo, esto es compatible con Google Chrome 73 y Safari 12.1, donde ambos se lanzaron en marzo de 2019; y Opera 60, que se lanzó en abril de 2019. - aullah

Esto actualmente (febrero de 2021) está suficientemente soportado, para llamarlo la solución. - theking2

Esta función debe manejar matrices multidimensionales junto con varios elementos con el mismo nombre.

Lo he estado usando durante un par de años hasta ahora:

jQuery.fn.serializeJSON=function() {
  var json = {};
  jQuery.map(jQuery(this).serializeArray(), function(n, i) {
    var _ = n.name.indexOf('[');
    if (_ > -1) {
      var o = json;
      _name = n.name.replace(/\]/gi, '').split('[');
      for (var i=0, len=_name.length; i<len; i++) {
        if (i == len-1) {
          if (o[_name[i]]) {
            if (typeof o[_name[i]] == 'string') {
              o[_name[i]] = [o[_name[i]]];
            }
            o[_name[i]].push(n.value);
          }
          else o[_name[i]] = n.value || '';
        }
        else o = o[_name[i]] = o[_name[i]] || {};
      }
    }
    else {
      if (json[n.name] !== undefined) {
        if (!json[n.name].push) {
          json[n.name] = [json[n.name]];
        }
        json[n.name].push(n.value || '');
      }
      else json[n.name] = n.value || '';      
    }
  });
  return json;
};

Respondido el 24 de Septiembre de 12 a las 20:09

Puedes hacerlo:

var frm = $(document.myform);
var data = JSON.stringify(frm.serializeArray());

Vea JSON.

Respondido 16 Feb 17, 16:02

Una línea (sin dependencias distintas de jQuery), utiliza un enlace de objeto fijo para la función transferida a map método.

$('form').serializeArray().map(function(x){this[x.name] = x.value; return this;}.bind({}))[0]

¿Que hace?

"id=2&value=1&comment=ok" => Object { id: "2", value: "1", comment: "ok" }

adecuado para aplicaciones web progresivas (se puede admitir fácilmente tanto la acción de envío de formulario regular como las solicitudes ajax)

Respondido 16 Oct 17, 12:10

Uso:

function form_to_json (selector) {
  var ary = $(selector).serializeArray();
  var obj = {};
  for (var a = 0; a < ary.length; a++) obj[ary[a].name] = ary[a].value;
  return obj;
}

Salida:

{"myfield": "myfield value", "passwordfield": "mypasswordvalue"}

Respondido 26 Abr '15, 08:04

De algunos mayor responder:

$('form input, form select').toArray().reduce(function(m,e){m[e.name] = $(e).val(); return m;},{})

Respondido 05 Feb 19, 07:02

Por lo que puedo decir, la diferencia es que su solución no depende de serializeArray para que tenga la libertad de elegir las entradas que desee (por ejemplo, puede incluir entradas deshabilitadas), ¿verdad? Es decir, esto no está acoplado a ningún formulario o al evento de envío, ¿es solo independiente por sí mismo? - davidgq

la única pequeña diferencia con la respuesta vinculada es que no se necesitan datos para crear una instancia, reduce devuelve el objeto. Esto no es independiente ya que toArray es de jQuery. - sitios

Encontré un problema con el código de Tobias Cohen (no tengo suficientes puntos para comentarlo directamente), que de lo contrario me funciona. Si tiene dos opciones de selección con el mismo nombre, ambas con valor = "", el código original producirá "nombre": "" en lugar de "nombre": ["", ""]

Creo que esto se puede solucionar agregando "|| o [this.name] == ''" a la primera condición if:

$.fn.serializeObject = function()
{
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name] || 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;
};

respondido 03 mar '11, 13:03

La simplicidad es lo mejor aquí. He usado un reemplazo de cadena simple con una expresión regular, y hasta ahora han funcionado a la perfección. No soy un experto en expresiones regulares, pero apuesto a que incluso puedes poblar objetos muy complejos.

var values = $(this).serialize(),
attributes = {};

values.replace(/([^&]+)=([^&]*)/g, function (match, name, value) {
    attributes[name] = value;
});

Respondido 26 Abr '15, 08:04

Usar solución de maček, Lo modifiqué para que funcione con la forma en que ASP.NET MVC maneja sus objetos anidados / complejos en el mismo formulario. Todo lo que tienes que hacer es modificar la pieza de validación a esto:

"validate": /^[a-zA-Z][a-zA-Z0-9_]*((?:\[(?:\d*|[a-zA-Z0-9_]+)\])*(?:\.)[a-zA-Z][a-zA-Z0-9_]*)*$/,

Esto coincidirá y luego mapeará correctamente elementos con nombres como:

<input type="text" name="zooName" />

Y también debes

<input type="text" name="zooAnimals[0].name" />

contestado el 23 de mayo de 17 a las 11:05

const formData = new FormData(form);

let formDataJSON = {};

for (const [key, value] of formData.entries()) {

    formDataJSON[key] = value;
}

contestado el 24 de mayo de 18 a las 21:05

Hay un complemento para hacer eso para jQuery, jquery.serializeJSON. Lo he usado con éxito en algunos proyectos ahora. Funciona a las mil maravillas.

Respondido 26 Abr '15, 08:04

la forma más simple y precisa que encontré para este problema fue usar complemento de barbacoa o esta uno (que tiene un tamaño de aproximadamente 0.5 K bytes).

también funciona con matrices multidimensionales.

$.fn.serializeObject = function()
{
	return $.deparam(this.serialize());
};

Respondido el 08 de diciembre de 15 a las 09:12

Esto parece funcionar muy bien. Hay un repositorio alternativo para jquery-deparam que incluye archivos de descripción para bower y npm. - alf eaton

Otra respuesta

document.addEventListener("DOMContentLoaded", function() {
  setInterval(function() {
    var form = document.getElementById('form') || document.querySelector('form[name="userprofile"]');
    var json = Array.from(new FormData(form)).map(function(e,i) {this[e[0]]=e[1]; return this;}.bind({}))[0];
    
    console.log(json)
    document.querySelector('#asJSON').value = JSON.stringify(json);
  }, 1000);
})
<form name="userprofile" id="form">
  <p>Name <input type="text" name="firstname" value="John"/></p>
  <p>Family name <input name="lastname" value="Smith"/></p>
  <p>Work <input name="employment[name]" value="inc, Inc."/></p>
  <p>Works since <input name="employment[since]" value="2017" /></p>
  <p>Photo <input type="file" /></p>
  <p>Send <input type="submit" /></p>
</form>

JSON: <textarea id="asJSON"></textarea>

Datos de formulario: https://developer.mozilla.org/en-US/docs/Web/API/FormData

Respondido 02 Abr '18, 17:04

Prefiero este enfoque porque: no tiene que iterar sobre 2 colecciones, puede obtener otras cosas que no sean "nombre" y "valor" si lo necesita, y puede desinfectar sus valores antes de almacenarlos en el objeto ( si tiene valores predeterminados que no desea almacenar, por ejemplo).

$.formObject = function($o) {
    var o = {},
        real_value = function($field) {
            var val = $field.val() || "";

            // additional cleaning here, if needed

            return val;
        };

    if (typeof o != "object") {
        $o = $(o);
    }

    $(":input[name]", $o).each(function(i, field) {
        var $field = $(field),
            name = $field.attr("name"),
            value = real_value($field);

        if (o[name]) {
            if (!$.isArray(o[name])) {
                o[name] = [o[name]];
            }

            o[name].push(value);
        }

        else {
            o[name] = value;
        }
    });

    return o;
}

Úselo así:

var obj = $.formObject($("#someForm"));

Solo probado en Firefox.

Respondido el 18 de junio de 10 a las 23:06

Me gusta la versión de samuel, pero creo que tiene un pequeño error. Normalmente, JSON se envía como

{"coreSKU": "PCGUYJS", "name_de": "lo que sea", ...

NO como

[{"coreSKU": "PCGUYJS"}, {"name_de": "lo que sea"}, ...

por lo que la función IMO debería leer:

App.toJson = function( selector ) {
    var o = {};
    $.map( $( selector ), function( n,i )
    {
        o[n.name] = $(n).val();
    });     
    return o;
}

y envolverlo en una matriz de datos (como también se esperaba comúnmente), y finalmente enviarlo como astring App.stringify ({data: App.toJson ('#cropform: input')})

Para el stringify, mira Pregunta 3593046 para la versión ajustada, en json2.js para la versión cubierta para todas las eventualidades. Eso debería cubrirlo todo :)

contestado el 23 de mayo de 17 a las 13:05

Gracias ... esto hace (como mencionaste) una diferencia pequeña pero muy importante. - Adarsha

Convierta cualquier cosa en un objeto (no probado por unidad)

<script type="text/javascript">
string = {};

string.repeat = function(string, count)
{
    return new Array(count+1).join(string);
}

string.count = function(string)
{
    var count = 0;

    for (var i=1; i<arguments.length; i++)
    {
        var results = string.match(new RegExp(arguments[i], 'g'));
        count += results ? results.length : 0;
    }

    return count;
}

array = {};

array.merge = function(arr1, arr2)
{
    for (var i in arr2)
    {
        if (arr1[i] && typeof arr1[i] == 'object' && typeof arr2[i] == 'object')
            arr1[i] = array.merge(arr1[i], arr2[i]);
        else
            arr1[i] = arr2[i]
    }

    return arr1;
}

array.print = function(obj)
{
    var arr = [];
    $.each(obj, function(key, val) {
        var next = key + ": ";
        next += $.isPlainObject(val) ? array.print(val) : val;
        arr.push( next );
      });

    return "{ " +  arr.join(", ") + " }";
}

node = {};

node.objectify = function(node, params)
{
    if (!params)
        params = {};

    if (!params.selector)
        params.selector = "*";

    if (!params.key)
        params.key = "name";

    if (!params.value)
        params.value = "value";

    var o = {};
    var indexes = {};

    $(node).find(params.selector+"["+params.key+"]").each(function()
    {
        var name = $(this).attr(params.key),
            value = $(this).attr(params.value);

        var obj = $.parseJSON("{"+name.replace(/([^\[]*)/, function()
        {
            return '"'+arguments[1]+'"';
        }).replace(/\[(.*?)\]/gi, function()
        {
            if (arguments[1].length == 0)
            {
                var index = arguments[3].substring(0, arguments[2]);
                indexes[index] = indexes[index] !== undefined ? indexes[index]+1 : 0;

                return ':{"'+indexes[index]+'"';
            }
            else
                return ':{"'+escape(arguments[1])+'"';
        })+':"'+value.replace(/[\\"]/gi, function()
        {
            return "\\"+arguments[0]; 
        })+'"'+string.repeat('}', string.count(name, ']'))+"}");

        o = array.merge(o, obj);
    });

    return o;
}
</script>

La salida de la prueba:

$(document).ready(function()
{
    console.log(array.print(node.objectify($("form"), {})));
    console.log(array.print(node.objectify($("form"), {selector: "select"})));
});

on

<form>
    <input name='input[a]' type='text' value='text'/>
    <select name='input[b]'>
        <option>select</option>
    </select>

    <input name='otherinput[c][a]' value='a'/>
    <input name='otherinput[c][]' value='b'/>
    <input name='otherinput[d][b]' value='c'/>
    <input name='otherinput[c][]' value='d'/>

    <input type='hidden' name='anotherinput' value='hidden'/>
    <input type='hidden' name='anotherinput' value='1'/>

    <input type='submit' value='submit'/>
</form>

rendirá:

{ input: { a: text, b: select }, otherinput: { c: { a: a, 0: b, 1: d }, d: { b: c } }, anotherinput: 1 }
{ input: { b: select } }

Respondido 19 Abr '12, 14:04

Para una solución rápida y moderna, utilice el JSONificar Complemento jQuery. El siguiente ejemplo se tomó literalmente del archivo README de GitHub. Todo el crédito a Kushal Pandya, autor del complemento.

Dado:

<form id="myform">
    <label>Name:</label>
    <input type="text" name="name"/>
    <label>Email</label>
    <input type="text" name="email"/>
    <label>Password</label>
    <input type="password" name="password"/>
</form>

Corriendo:

$('#myform').jsonify();

Produce:

{"name":"Joe User","email":"joe@example.com","password":"mypass"}

Si desea hacer un POST de jQuery con este objeto JSON:

$('#mybutton').click(function() {
    $.post('/api/user', JSON.stringify($('#myform').jsonify()));
}

Respondido el 06 de Septiembre de 13 a las 19:09

Encontré un problema con la solución seleccionada.

Cuando se utilizan formularios que tienen nombres basados ​​en matrices, la función jQuery serializeArray () realmente muere.

Tengo un marco PHP que usa nombres de campo basados ​​en matrices para permitir que el mismo formulario se coloque en la misma página varias veces en varias vistas. Esto puede ser útil para agregar, editar y eliminar en la misma página sin modelos de formulario en conflicto.

Como quería seralizar los formularios sin tener que eliminar esta funcionalidad básica absoluta, decidí escribir mi propio seralizeArray ():

        var $vals = {};

        $("#video_edit_form input").each(function(i){
            var name = $(this).attr("name").replace(/editSingleForm\[/i, '');

            name = name.replace(/\]/i, '');

            switch($(this).attr("type")){
                case "text":
                    $vals[name] = $(this).val();
                    break;
                case "checkbox":
                    if($(this).attr("checked")){
                        $vals[name] = $(this).val();
                    }
                    break;
                case "radio":
                    if($(this).attr("checked")){
                        $vals[name] = $(this).val();
                    }
                    break;
                default:
                    break;
            }
        });

Tenga en cuenta: Esto también funciona fuera del envío del formulario (), por lo que si se produce un error en el resto de su código, el formulario no se enviará si coloca un botón de enlace que dice "guardar cambios".

También tenga en cuenta que esta función nunca debe usarse para validar el formulario solo para recopilar los datos y enviarlos al servidor para su validación. El uso de un código tan débil y asignado en masa causará XSS, etc.

Respondido 24 Abr '15, 20:04

Tuve el mismo problema últimamente y salí con este complemento .toJSON jQuery que convierte un formulario en un objeto JSON con la misma estructura. Esto también es especialmente útil para formularios generados dinámicamente en los que desea permitir que su usuario agregue más campos en lugares específicos.

El punto es que es posible que desee construir un formulario para que tenga una estructura en sí mismo, así que digamos que desea crear un formulario donde el usuario inserte sus lugares favoritos en la ciudad: puede imaginar este formulario para representar un <places>...</places> Elemento XML que contiene una lista de lugares que le gustan al usuario, por lo tanto, una lista de <place>...</place> elementos cada uno que contiene, por ejemplo, un <name>...</name> elemento, un <type>...</type> elemento y luego una lista de <activity>...</activity> elementos para representar las actividades que puede realizar en dicho lugar. Entonces su estructura XML sería así:

<places>

    <place>

        <name>Home</name>
        <type>dwelling</type>

        <activity>sleep</activity>
        <activity>eat</activity>
        <activity>watch TV</activity>

    </place>

    <place>...</place>

    <place>...</place>

</places>

Qué bueno sería tener un objeto JSON fuera de esto que representaría esta estructura exacta para que pueda:

  • Almacene este objeto como está en cualquier CouchDB-como base de datos
  • Léalo desde el lado del servidor $ _POST [] y recupere una matriz anidada correctamente que luego puede manipular semánticamente
  • Use algún script del lado del servidor para convertirlo en un archivo XML bien formado (incluso si no conoce su estructura exacta a priori)
  • Úselo de alguna manera como está en cualquier Node.js-como script de servidor

Bien, ahora tenemos que pensar cómo un formulario puede representar un archivo XML.

Por supuesto, el <form> la etiqueta es la root, pero luego tenemos eso <place> elemento que es un contenedor y no un elemento de datos en sí mismo, por lo que no podemos usar una etiqueta de entrada para él.

Aquí es donde el <fieldset> ¡La etiqueta es útil! Usaremos <fieldset> etiquetas para representar todos los elementos del contenedor en nuestro formulario / representación XML y así llegar a un resultado como este:

<form name="places">

    <fieldset name="place">

        <input type="text" name="name"/>
        <select name="type">
            <option value="dwelling">Dwelling</option>
            <option value="restoration">Restoration</option>
            <option value="sport">Sport</option>
            <option value="administrative">Administrative</option>
        </select>

        <input type="text" name="activity"/>
        <input type="text" name="activity"/>
        <input type="text" name="activity"/>

    </fieldset>

</form>

Como puede ver en este formulario, estamos rompiendo la regla de los nombres únicos, pero esto está bien porque se convertirán en una matriz de elementos, por lo que solo se hará referencia a ellos por su índice dentro de la matriz.

En este punto puedes ver como no hay name="array[]" como nombre dentro del formulario y todo es bonito, simple y semántico.

Ahora queremos que este formulario se convierta en un objeto JSON que se verá así:

{'places':{

    'place':[

        {

            'name': 'Home',
            'type': 'dwelling',

            'activity':[

                 'sleep',
                 'eat',
                 'watch TV'

            ]

        },

        {...},

        {...}

    ]

}}

Para hacer esto he desarrollado este complemento de jQuery aquí que alguien ayudó a optimizar en este Revisión de código hilo y se ve así:

$.fn.toJSO = function () {
    var obj = {},
        $kids = $(this).children('[name]');
    if (!$kids.length) {
        return $(this).val();
    }
    $kids.each(function () {
        var $el = $(this),
            name = $el.attr('name');
        if ($el.siblings("[name=" + name + "]").length) {
            if (!/radio|checkbox/i.test($el.attr('type')) || $el.prop('checked')) {
                obj[name] = obj[name] || [];
                obj[name].push($el.toJSO());
            }
        } else {
            obj[name] = $el.toJSO();
        }
    });
    return obj;
};

Yo tambien hice esta entrada de blog para explicar esto más.

Esto convierte todo en un formulario a JSON (incluso radio y casillas de verificación) y todo lo que le queda por hacer es llamar

$.post('script.php',('form').toJSO(), ...);

Sé que hay muchas formas de convertir formularios en objetos JSON y seguro .serialize() y .serializeArray() funcionan muy bien en la mayoría de los casos y en su mayoría están destinados a ser utilizados, pero creo que toda esta idea de escribir un formulario como una estructura XML con nombres significativos y convertirlo en un objeto JSON bien formado Vale la pena intentarlo, también el hecho de que puede agregar etiquetas de entrada del mismo nombre sin preocuparse es muy útil si necesita recuperar datos de formularios generados dinámicamente.

¡Espero que esto ayude a alguien!

Respondido 13 Abr '17, 13:04

¿que estás tratando de hacer? - Onheiron

Yo mismo codifiqué un formulario en un objeto JavaScript multidimensional para usarlo en producción. El resultado es https://github.com/serbanghita/formToObject.js.

Respondido 26 Abr '15, 08:04

Usé una variación de esto para una implementación muy específica, ¡muchas gracias! - Chris Baker

Gracias por hacerme saber que es útil. Tengo algunas características entrantes para rodar y esto me motiva. - Șerban Ghiță

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.