使用jQuery将表单数据转换为JavaScript对象
如何将表单的所有元素转换为JavaScript对象?
我想有一些从我的窗体自动构buildJavaScript对象的方式,而不必循环每个元素。 我不想要一个string,由$('#formid').serialize();
,也不希望由$('#formid').serializeArray();
返回的映射$('#formid').serializeArray();
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; }
注意隐藏的字段与真实input名称相同,因为它们将被覆盖。
将表单转换为JSON像一个老板
目前来源在GitHub和凉亭。
$ bower安装jquery-serialize-object
下面的代码现在已经被弃用了 。
下面的代码可以处理各种input名称; 并按照您的预期处理它们。
例如:
<!-- 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);
有什么问题:
var data = {}; $(".form-selector").serializeArray().map(function(x){data[x.name] = x.value;});
Tobias Cohen解决scheme的固定版本。 这个正确处理像0
和''
这样的falsy值。
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
我喜欢使用Array.prototype.reduce
因为它是一个Array.prototype.reduce
,它不依赖于Underscore.js或类似:
$('#formid').serializeArray() .reduce(function(a, x) { a[x.name] = x.value; return a; }, {});
这与使用Array.prototype.map
的答案类似,但不需要使用额外的对象variablesArray.prototype.map
您的范围。 一站式购物。
重要提示 :具有重复name
属性的input的表单是有效的HTML,实际上是一种常用的方法。 在这种情况下使用任何答案将是不适当的(因为对象键必须是唯一的)。
所有这些答案对我来说似乎都是如此。 有一点可以说是简单的。 只要所有的表单input都具有名称属性设置,这应该只是吉姆丹迪。
$('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 (eg JSON.stringify?) });
如果你正在使用Underscore.js,你可以使用相对简洁:
_.object(_.map($('#myform').serializeArray(), _.values))
没有检查每个元素,实在没有办法做到这一点。 你真正想知道的是“有人已经写了一个方法,将表单转换成JSON对象? 像下面的东西应该工作 – 请注意,它只会给你通过POST返回的表单元素(必须有一个名称)。 这没有经过testing 。
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; }
好的,我知道这个问题已经得到了高度的回答,但最近又有人提出了另一个类似的问题 ,我也被引导到了这个问题上。 我也想提供我的解决scheme,因为它提供了一个优于接受的解决scheme的优势:您可以包含禁用的表单元素(这有时很重要,这取决于您的UI的function)
这是我从另一个SO问题的答案:
最初,我们使用jQuery的serializeArray()
方法,但不包括被禁用的表单元素。 我们经常会禁用与页面上其他来源“同步”的表单元素,但是我们仍然需要将数据包含在序列化的对象中。 所以serializeArray()
出来了。 我们使用:input
select器来获取给定容器中的所有input元素(包括enabled和disabled),然后使用$.map()
来创build我们的对象。
var inputs = $("#container :input"); var obj = $.map(inputs, function(n, i) { var o = {}; o[n.name] = $(n).val(); return o; }); console.log(obj);
请注意,为了这个工作,你的每个input将需要一个name
属性,这将是结果对象的属性的名称。
这实际上是从我们使用的稍微修改。 我们需要创build一个结构为.NET IDictionary的对象,所以我们使用这个:(我在这里提供它,以防万一它有用)
var obj = $.map(inputs, function(n, i) { return { Key: n.name, Value: $(n).val() }; }); console.log(obj);
我喜欢这两种解决scheme,因为它们是$.map()
函数的简单使用,并且可以完全控制select器(所以,最终包含在结果对象中的元素)。 另外,不需要额外的插件。 普通的旧jQuery。
这个函数应该处理multidimensional array和多个具有相同名字的元素。
到目前为止,我一直在使用它几年:
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; };
你可以这样做:
var frm = $(document.myform); var data = JSON.stringify(frm.serializeArray());
看到JSON 。
使用:
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"}
简单是最好的。 我用一个简单的stringreplace正则expression式,他们迄今为止像一个魅力工作。 我不是一个正规的expression专家,但我敢打赌,你甚至可以填充非常复杂的对象。
var values = $(this).serialize(), attributes = {}; values.replace(/([^&]+)=([^&]*)/g, function (match, name, value) { attributes[name] = value; });
宽度全部给出答案有一些问题是…
如果像name[key]
那样input数组的name[key]
,但是会像这样产生
name:{ key : value }
例如:如果我有这样的forms。
<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 getFormData2Object(form){ var un_array = form.serializeArray(); var _array = {}; $.map(un_array, function(n, i){ if(n.name.indexOf('[') > -1 ){ var array = n.name.match(/\[(.*?)\]/); var key = n.name.replace(array[1],"").replace('[',"").replace(']',""); if(!_array[key]){ _array[key] = {}; } _array[key][array[1]] = n['value']; }else{ _array[n['name']] = n['value']; } }); return _array; } getFormData2Object($('form'))
使用maček的解决scheme ,我将其修改为使用ASP.NET MVC在同一表单上处理其嵌套/复杂对象的方式。 你所要做的就是将validation片修改为:
"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" />
从一些较旧的答案:
$('form input,select').toArray().reduce(function(m,e){m[e.name] = $(e).val(); return m;},{})
我发现这个问题最简单和最准确的方法是使用bbq插件或这个(大约0.5K字节大小)。
它也适用于multidimensional array。
$.fn.serializeObject = function() { return $.deparam(this.serialize()); };
我发现Tobias Cohen的代码存在一个问题(我没有足够的观点来直接发表评论),否则这些代码对我很有用。 如果你有两个同名的选项,都是value =“”,原来的代码会产生“name”:“”而不是“name”:[“”,“”]
我认为这可以通过添加“|| 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; };
如果您试图将所有表单字段转换为JSON以便通过Ajax提交此表单,则此处为一个jQuery表单插件 。
有一个插件可以做到这一点的jQuery, jquery.serializeJSON 。 我现在已经在一些项目上成功地使用了它。 它像一个魅力。
将任何东西变成一个对象(不是unit testing)
<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>
testing的输出:
$(document).ready(function() { console.log(array.print(node.objectify($("form"), {}))); console.log(array.print(node.objectify($("form"), {selector: "select"}))); });
上
<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>
会产生:
{ input: { a: text, b: select }, otherinput: { c: { a: a, 0: b, 1: d }, d: { b: c } }, anotherinput: 1 } { input: { b: select } }
我发现所选解决scheme存在问题。
当使用具有基于数组的名称时,jQuery serializeArray()函数实际上会死亡。
我有一个PHP框架,使用基于数组的字段名称,允许多个视图多次将相同的表单放在同一个页面上。 这可以很方便地同时添加,编辑和删除,而没有冲突的表单模型。
因为我想seralize的forms,而不必采取这个绝对的基本function,我决定写我自己的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; } });
请注意:这也适用于表单submit()之外,所以如果在代码的其余部分发生错误,表单将不会提交,如果你放在一个链接button说“保存更改”。
还要注意,这个函数决不能用来validation表单,只收集数据发送到服务器端进行validation。 使用这种弱和质量分配的代码将导致XSS等。
我最近有同样的问题,并出来了这个.JSON jQuery插件转换成相同结构的JSON对象的forms。 这对于dynamic生成的表单也特别有用,您希望让用户在特定位置添加更多字段。
关键是你可能真的想build立一个表单,以便它本身具有一个结构,所以假设你想制作一个表单,用户在城里插入他最喜欢的地方:你可以想象这个表单代表一个<places>...</places>
包含用户喜欢的地方列表的XML元素,因此列出<place>...</place>
元素,每个元素包含例如<name>...</name>
元素,a <type>...</type>
元素,然后列出<activity>...</activity>
元素来表示您可以在这样的地方执行的活动。 所以你的XML结构将是这样的:
<places> <place> <name>Home</name> <type>dwelling</type> <activity>sleep</activity> <activity>eat</activity> <activity>watch TV</activity> </place> <place>...</place> <place>...</place> </places>
如果有一个JSON对象离开这个代表这个确切结构的东西,那么你将能够:
- 像在任何类似CouchDB的数据库中一样存储这个对象
- 从你的$ _POST []服务器端读取它,然后检索一个正确的嵌套数组,然后可以进行语义操作
- 使用一些服务器端脚本将其转换成格式良好的XML文件(即使您事先并不知道其确切的结构)
- 只是以某种方式像在任何类似Node.js的服务器脚本中一样使用它
好的,现在我们需要考虑一个表单如何表示一个XML文件。
当然, <form>
标签是root
,但是我们有<place>
元素,它是一个容器,而不是数据元素本身,所以我们不能使用它的input标签。
这就是<fieldset>
标签派上用场的地方! 我们将使用<fieldset>
标签来表示我们的表单/ XML表示中的所有容器元素,因此得到这样的结果:
<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>
正如你在这个表格中看到的那样,我们打破了唯一名称的规则,但是这样做是可以的,因为它们将被转换成一个元素数组,因此它们只会被数组中的索引所引用。
在这一点上,你可以看到表单里面没有name="array[]"
这样的名字,一切都很漂亮,简单而且语义化。
现在我们要把这个表单转换成一个JSON对象,如下所示:
{'places':{ 'place':[ { 'name': 'Home', 'type': 'dwelling', 'activity':[ 'sleep', 'eat', 'watch TV' ] }, {...}, {...} ] }}
要做到这一点,我已经在这里开发了这个jQuery插件 ,有人帮助在这个代码审查线程优化,看起来像这样:
$.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; };
我也做了这个博客文章来解释这一点。
这将表单中的所有内容都转换为JSON(即使是收音机和checkbox),您只需要调用即可
$.post('script.php',('form').toJSO(), ...);
我知道有很多方法可以将表单转换成JSON对象,并且确实.serialize()
和.serializeArray()
在大多数情况下都很.serializeArray()
,而且大多都是用来使用的,但是我认为把表单写成XML结构with meaningful names and converting it into a well-formed JSON object is worth the try, also the fact you can add same-name input tags without worrying is very useful if you need to retrive dynamically generated forms data.
我希望这可以帮助别人!
I prefer this approach because: you don't have to iterate over 2 collections, you can get at things other than "name" and "value" if you need to, and you can sanitize your values before you store them in the object (if you have default values that you don't wish to store, for example).
$.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; }
Use like so:
var obj = $.formObject($("#someForm"));
Only tested in Firefox.
For a quick, modern solution, use the JSONify jQuery plugin. The example below is taken verbatim from the GitHub README. All credit to Kushal Pandya, author of the plugin.
鉴于:
<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>
运行:
$('#myform').jsonify();
生产:
{"name":"Joe User","email":"joe@example.com","password":"mypass"}
If you want to do a jQuery POST with this JSON object:
$('#mybutton').click(function() { $.post('/api/user', JSON.stringify($('#myform').jsonify())); }
I coded a form to a multidimensional JavaScript object myself to use it in production. The result is https://github.com/serbanghita/formToObject.js .
One-liner (no dependencies other than jQuery), uses fixed object binding for function passsed to map
method.
$('form').serializeArray().map(function(x){this[x.name] = x.value; return this;}.bind({}))[0]
What it does?
"id=2&value=1&comment=ok" => Object { id: "2", value: "1", comment: "ok" }
suitable for progressive web apps (one can easily support both regular form submit action as well as ajax requests)
I wouldn't use this on a live site due to XSS attacks and probably plenty of other issues, but here's a quick example of what you could do:
$("#myform").submit(function(){ var arr = $(this).serializeArray(); var json = ""; jQuery.each(arr, function(){ jQuery.each(this, function(i, val){ if (i=="name") { json += '"' + val + '":'; } else if (i=="value") { json += '"' + val.replace(/"/g, '\\"') + '",'; } }); }); json = "{" + json.substring(0, json.length - 1) + "}"; // do something with json return false; });
I like samuels version, but I believe it has a small error. Normally JSON is sent as
{"coreSKU":"PCGUYJS","name_de":"whatever",…
NOT as
[{"coreSKU":"PCGUYJS"},{"name_de":"whatever"},…
so the function IMO should read:
App.toJson = function( selector ) { var o = {}; $.map( $( selector ), function( n,i ) { o[n.name] = $(n).val(); }); return o; }
and to wrap it in data array (as commonly expected, too), and finally send it as astring App.stringify( {data:App.toJson( '#cropform :input' )} )
For the stringify look at Question 3593046 for the lean version, at json2.js for the every-eventuality-covered version. That should cover it all 🙂
If you are sending a form with JSON you must remove [] in sending the string. You can do that with the jQuery function serializeObject():
var frm = $(document.myform); var data = JSON.stringify(frm.serializeObject()); $.fn.serializeObject = function() { var o = {}; //var a = this.serializeArray(); $(this).find('input[type="hidden"], input[type="text"], input[type="password"], input[type="checkbox"]:checked, input[type="radio"]:checked, select').each(function() { if ($(this).attr('type') == 'hidden') { //If checkbox is checked do not take the hidden field var $parent = $(this).parent(); var $chb = $parent.find('input[type="checkbox"][name="' + this.name.replace(/\[/g, '\[').replace(/\]/g, '\]') + '"]'); if ($chb != null) { if ($chb.prop('checked')) return; } } if (this.name === null || this.name === undefined || this.name === '') return; var elemValue = null; if ($(this).is('select')) elemValue = $(this).find('option:selected').val(); else elemValue = this.value; if (o[this.name] !== undefined) { if (!o[this.name].push) { o[this.name] = [o[this.name]]; } o[this.name].push(elemValue || ''); } else { o[this.name] = elemValue || ''; } }); return o; }