使用jQuery将表单数据转换为JavaScript对象

Yisroel 1580 javascript jquery serialization json

如何将表单的所有元素转换为JavaScript对象?

我想有一些方法从我的表单中自动构建一个JavaScript对象,而不必遍历每个元素.我不想要返回的字符串,$('#formid').serialize();也不想要返回的地图$('#formid').serializeArray();

Tobias Cohen.. 1631

serializeArray已经做到了.您只需按照所需格式按摩数据:

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;
}

注意与实际输入同名的隐藏字段,因为它们将被覆盖.

  • 你的意思是"为什么要使用serializeArray来获取数据?" 因为已经编写了serializeArray,所以在多个浏览器中进行单元测试,理论上可以在更高版本的jQuery中进行改进.您编写的代码越少,直接访问DOM元素等不一致的东西,代码就越稳定. (67认同)
  • 请注意,serializeArray()不会包含已禁用的元素.我经常禁用与页面上其他元素同步的输入元素,但我仍然希望它们包含在我的序列化对象中.你最好使用`$ .map($("#container:input"),function(n,i){/*n.name和$(n).val()*/});如果您需要包含已禁用的元素. (55认同)
  • @TobiasCohen它没有按预期处理`foo [bar]`-type输入,更不用说大多数其他输入名称变种了.在对这个问题的浅层解决方案感到非常沮丧之后,我最终编写了自己的jQuery插件 - 我在这个问题的答案中提供了详细信息. (22认同)
  • @macek我知道这已经有几个月了,但是从什么时候开始数组使用非数字索引?没有人应该输入输入foo [bar]并希望将其视为数组.你是否混淆数组和哈希?是的,[]通常被理解为访问者,但不仅仅是数组.还说它是有效的HTML而不是HTML规范是矛盾的.是的,浏览器可能不会阻塞它,但没有多少网络服务器会知道如何反序列化它们就像数组一样.为什么?因为它不在HTML规范中.因此,它确实无效. (6认同)
  • 正如tvanfosson所说,为什么要重复两次收集? (4认同)
  • @macek我想你可能正在寻找一个不同问题的答案.`foo [bar]`样式输入命名在许多Web框架中是常见的约定,但它肯定不是HTML表单的标准部分,在问题中没有提到,我没有尝试在这里处理它. (3认同)
  • @TobiasCohen,我从未说过HTML规范说应该特别对待它们.我只是在争论`foo [bar]`类型的名称是完全有效的,而`[]`通常被理解为数组访问器; 为什么不这样处理呢?或者说它有点不同,在什么情况下你会命名输入`foo [bar]`并且不希望将`foo`视为数组? (3认同)
  • jQuery插件serializeJSON使用serailizeArray将复杂的表单序列化为与Rails params相同的格式:https://github.com/marioizquierdo/jquery.serializeJSON (3认同)
  • @TobiasCohen,我理解不想支持它,但是说它"不是HTML表单的标准部分"既不正确也不是有效的反点.名为`foo [bar]`的输入肯定是有效的; 最重要的是,增加对预期功能的支持会产生更强大和灵活的解决方案. (2认同)
  • @macek你能否告诉我HTML规范中的哪个部分应该特别处理以这种格式命名的输入? (2认同)
  • jQuery本身应该在最近的下一个版本中提供这个功能,你不这么认为吗? (2认同)
  • 来自http://css-tricks.com/snippets/jquery/serialize-form-to-json/优秀代码段 (2认同)

maček.. 441

将表单转换为JSON LIKE A BOSS


目前的消息来源是GitHub和bower.

$ bower安装jquery-serialize-object


现在不推荐使用以下代码.

以下代码可以使用各种输入名称; 并按照您的期望处理它们.

例如:

<!-- 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"
          }
        }
      }
    }
  }
}

用法

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

巫术(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);

  • 所以,这很有效.但它的名字错误:它不会返回JSON,顾名思义.相反,它返回一个对象文字.此外,检查hasOwnProperty非常重要,否则您的数组会附加到其原型上的任何内容,例如:{numbers:["1","3",indexOf:function(){...}]} (17认同)
  • 此解决方案应位于顶部,因为它将嵌套键的问题作为表单元素名称处理. (8认同)
  • @frontendbeauty实际上,toJSON正是规范所说的应该被称为:https://developer.mozilla.org/en/JSON#toJSON()_method一个不幸的用词不当. (5认同)
  • @Marek,我在[jsfiddle](http://jsfiddle.net/y8MPQ/1/)上做了一个测试.诀窍是正确命名您的选择.`<select name ="foo"multiple ="multiple">`在任何情况下都不起作用.但是,如果使用`[]`,如`<select name ="bar []"multiple ="multiple">`,它会正常工作:) (4认同)
  • 想要指出https://github.com/serbanghita/formToObject是一个类似的JavaScript方法(不需要第三方库),它可以完成同样的工作.支持'multiple',忽略'禁用'元素. (3认同)
  • 我同意这是更强大的解决方案.如果您不仅仅拥有一组平面数据,那么您将需要此解决方案.在我的情况下,我有子类型的数组(例如,预订有一系列付款).此解决方案返回了一系列名为Payments的子文档,其中包含每个付款属性.爱它! (2认同)
  • 非常感谢.我所见过的多维形式的最佳解决方案! (2认同)
  • 请说明“现在不建议使用以下代码”。手段。赞成什么? (2认同)

mkschreder.. 277

有什么不对:

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

  • `$(this).serializeArray().reduce(function(m,o){m [o.name] = o.value; return m;},{})` (37认同)
  • 如果你没有返回任何东西,为什么不用`.each`而不是`.map` ?? (21认同)
  • 这很简单,因为它超级天真...不处理具有相同名称的复选框.每次它都会覆盖之前的检查项目.你肯定需要一些输入类型检测来确保它被正确序列化. (10认同)
  • 如果你想要一个纯粹的jQuery解决方案,你可以使用`var form = {}; $ .each($(this).serializeArray(),function(i,field){form [field.name] = field.value ||"";});` (5认同)
  • @LayZee - 如果没有选择,你为什么要在你的后端?如果必须选择一个选项,请在序列化之前验证输入. (2认同)

Daniel X Moo.. 102

Tobias Cohen解决方案的固定版本.这个正确处理像0和的假值''.

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;
};

和CoffeeScript版本为您的编码方便:

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


Ethan Brown.. 57

我喜欢使用,Array.prototype.reduce因为它是一个单行,并且它不依赖于Underscore.js等:

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

这与使用的答案类似Array.prototype.map,但您不需要使用其他对象变量来混淆范围.一站式购物.

重要说明:具有重复name属性的输入的表单是有效的HTML,实际上是一种常用方法.在这种情况下,使用此线程中的任何答案都是不合适的(因为对象键必须是唯一的).

  • 我为这个10,000名员工组织工作. (4认同)
  • 没错,但填充容易.此外,由于微软在IE11企业模式方面的出色工作,IE8令人头疼*几乎结束了 - 我不再满足于使用IE8的个人用户,但是当一个拥有10,000名员工的组织都使用IE8时......出现了不同.幸运的是,微软正在努力解决这个问题. (3认同)

小智.. 30

所有这些答案对我来说都是如此.为简单起见,有一些话要说.只要您的所有表单输入都具有name属性设置,这应该只是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?)
});

  • 但是,不处理嵌套表单数据,这就是为什么答案变得更复杂. (3认同)

olleicua.. 23

如果您使用的是Underscore.js,则可以使用相对简洁的:

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


tvanfosson.. 22

没有检查每个元素就没有办法做到这一点.你真正想知道的是"还有其他人已经编写了一个将表单转换为JSON对象的方法吗?" 类似下面的内容应该有效 - 请注意,它只会为您提供通过POST返回的表单元素(必须具有名称).这没有经过测试.

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;
}

  • 使用serializedArray是可行的,但实际上您将对集合进行两次迭代-一次生成数组,然后遍历数组。我认为没有必要。 (2认同)

Samuel Meach.. 17

好吧,我知道这已经有了一个高度赞成的答案,但最近又提出了另一个类似的问题,我也被引导到了这个问题.我也想提供我的解决方案,因为它提供了优于已接受的解决方案的优势:您可以包含已禁用的表单元素(这有时很重要,具体取决于您的UI功能)

以下是我对其他SO问题的回答:

最初,我们使用jQuery的serializeArray()方法,但不包括禁用的表单元素.我们经常会禁用与页面上其他来源"同步"的表单元素,但我们仍然需要将数据包含在序列化对象中.好serializeArray()了.我们使用:input选择器获取给定容器中的所有输入元素(启用和禁用),然后$.map()创建我们的对象.

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

请注意,为此,每个输入都需要一个name属性,该属性将是结果对象的属性名称.

实际上,这与我们使用的内容略有不同.我们需要创建一个结构为.NET IDictionary的对象,所以我们使用了这个:(我在这里提供它,以防它有用)

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

我喜欢这两种解决方案,因为它们是$.map()函数的简单用法,并且您可以完全控制选择器(因此,最终包含在结果对象中的元素).此外,不需要额外的插件.简单的旧jQuery.

  • 我在一个项目中尝试过这个,使用`map`就像这样创建一个具有单个属性的对象数组,它不会将属性全部折叠到一个对象中. (6认同)

小智.. 16

此函数应处理多维数组以及具有相同名称的多个元素.

到目前为止,我已经使用它几年了:

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;
};


Bhavik Hiran.. 16

有了所有的给定答案,有一些问题是......

如果输入名称像数组一样name[key],但它会像这样生成

name:{ key : value }

例如: 如果我有这样的形式.

<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>

然后它将使用所有给定的答案生成这样的对象.

Object {
    name : 'value',
    name1[key1] : 'value1',
    name2[key2] : 'value2',
    name3[key3] : 'value3', 
}

但它必须生成如下所示,任何人都希望如下所示.

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

然后尝试以下js代码.

(function($){
    $.fn.getForm2obj = function(){
        var _ = {},_t=this;
        this.c = function(k,v){ eval("c = typeof "+k+";"); if(c == 'undefined') _t.b(k,v);}
        this.b = function(k,v,a = 0){ if(a) eval(k+".push("+v+");"); else eval(k+"="+v+";"); };
        $.map(this.serializeArray(),function(n){
            if(n.name.indexOf('[') > -1 ){
                var keys = n.name.match(/[a-zA-Z0-9_]+|(?=\[\])/g),le = Object.keys(keys).length,tmp = '_';
                $.map(keys,function(key,i){
                    if(key == ''){
                        eval("ale = Object.keys("+tmp+").length;");
                        if(!ale) _t.b(tmp,'[]');
                        if(le == (i+1)) _t.b(tmp,"'"+n['value']+"'",1);
                        else _t.b(tmp += "["+ale+"]",'{}');
                    }else{
                        _t.c(tmp += "['"+key+"']",'{}');
                        if(le == (i+1)) _t.b(tmp,"'"+n['value']+"'");
                    }
                });
            }else _t.b("_['"+n['name']+"']","'"+n['value']+"'");
        });
        return _;
    }
})(jQuery);
console.log($('form').getForm2obj());
$('form input').change(function(){
    console.clear();
    console.log($('form').getForm2obj());
});
<!DOCTYPE html><html><head>
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <title>Convert form data to JavaScript object with jQuery</title>
</head>
<body>
    <form>
        <input type="checkbox" name="name4[]" value="1" checked="checked">1
        <input type="checkbox" name="name4[]" value="2">2
        <input type="checkbox" name="name4[]" value="3">3<br>
        <input type="radio" name="gender" value="male" checked="checked">male 
        <input type="radio" name="gender" value="female"> female
        <input name="name" value="value" >
        <input name="name1[key1]" value="value1" >
        <input name="name2[key2]" value="value2" >
        <input name="name3[key3]" value="value3" ><br><br>
        <input name="one[another][another_one]" value="value4" >
    </form>
</body></html>


小智.. 15

你可以这样做:

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

JSON.


test30.. 13

单行(除了jQuery之外没有依赖项),使用固定对象绑定来传递给map方法的函数.

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

它能做什么?

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

适用于渐进式网络应用程序(可以轻松支持常规表单提交操作以及ajax请求)


Adrian Seele.. 12

使用:

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;
}

输出:

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


小智.. 7

简洁是最好的.我使用了一个简单的字符串替换和正则表达式,到目前为止它们就像一个魅力.我不是正规表达专家,但我敢打赌,你甚至可以填充非常复杂的对象.

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

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


juanpastas.. 7

从一些较旧的答案:

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


小智.. 6

使用maček的解决方案,我修改它以使用ASP.NET MVC在同一表单上处理其嵌套/复杂对象的方式.您所要做的就是将验证件修改为:

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

这将匹配,然后正确映射元素,如下所示:

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

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


小智.. 5

我发现托比亚斯科恩的代码存在问题(我没有足够的要点直接评论它),否则这对我有用.如果您有两个具有相同名称的选项,两者都带有值="",则原始代码将生成"name":""而不是"name":["",""]

我认为这可以通过在第一个if条件中添加"|| o [this.name] ==''"来解决:

$.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;
};


Roey.. 5

我发现这个问题的最简单,最准确的方法是使用烧烤插件或这一个(大约是0.5K字节大小).

它也适用于多维数组.

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


归档时间:

查看次数:

949380 次

最近记录:

1 年 前