如何将表单的所有元素转换为JavaScript对象?
我希望有某种方法从表单自动构建JavaScript对象,而不必遍历每个元素。我不希望使用$('#formid').serialize();返回的字符串;,我也不希望$('#formid').serializeArray()返回映射;
如何将表单的所有元素转换为JavaScript对象?
我希望有某种方法从表单自动构建JavaScript对象,而不必遍历每个元素。我不希望使用$('#formid').serialize();返回的字符串;,我也不希望$('#formid').serializeArray()返回映射;
当前回答
我最近遇到了同样的问题,并推出了这个.toJSONjQuery插件,它将表单转换为具有相同结构的JSON对象。这对于动态生成的表单也特别有用,因为您希望用户在特定位置添加更多字段。
重点是你可能实际上想要构建一个表单,这样它本身就有一个结构,所以让我们假设你想要创建一个用户在城镇中插入他最喜欢的位置的表单:你可以想象这个表单代表一个<places></places>XML元素,包含用户喜欢的位置列表,因此是<place>列表</place>元素,每个元素包含例如<name></name>元素,一个<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>标记是根,但是我们有一个<place>元素,它是一个容器,而不是数据元素本身,所以我们不能为它使用输入标记。
这里是<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插件,有人在这个CodeReview线程中帮助优化了这个插件,看起来像这样:
$.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(甚至是单选和复选框),您只需调用
$.post('script.php',('form').toJSO(), ...);
我知道有很多方法可以将表单转换为JSON对象,当然.serialize()和.serializeArray()在大多数情况下都非常有效,而且主要是为了使用,但我认为将表单编写为具有有意义名称的XML结构并将其转换为格式良好的JSON对象的整个想法值得一试,如果您需要检索动态生成的表单数据,那么可以添加同名输入标记而不必担心这一事实也非常有用。
我希望这对某人有所帮助!
其他回答
此代码适用于我:
var data = $('#myForm input, #myForm select, #myForm textarea').toArray().reduce(function (m, e) {
m[e.name] = $(e).val();
return m;
}, {});
这是对Tobias Cohen函数的改进,该函数在多维数组中运行良好:
http://jsfiddle.net/BNnwF/2/
然而,这不是一个jQuery插件,但如果您想这样使用它,只需几秒钟就可以将它变成一个:只需替换函数声明包装器:
function serializeFormObject(form)
{
...
}
具有:
$.fn.serializeFormObject = function()
{
var form = this;
...
};
我想这与梅斯克的解决方案相似,因为它做了相同的事情,但我认为这有点干净和简单。我还将macek的测试用例输入添加到小提琴中,并添加了一些额外的输入。到目前为止,这对我来说很好。
function serializeFormObject(form)
{
function trim(str)
{
return str.replace(/^\s+|\s+$/g,"");
}
var o = {};
var a = $(form).serializeArray();
$.each(a, function() {
var nameParts = this.name.split('[');
if (nameParts.length == 1) {
// New value is not an array - so we simply add the new
// value to the result object
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
}
else {
// New value is an array - we need to merge it into the
// existing result object
$.each(nameParts, function (index) {
nameParts[index] = this.replace(/\]$/, '');
});
// This $.each merges the new value in, part by part
var arrItem = this;
var temp = o;
$.each(nameParts, function (index) {
var next;
var nextNamePart;
if (index >= nameParts.length - 1)
next = arrItem.value || '';
else {
nextNamePart = nameParts[index + 1];
if (trim(this) != '' && temp[this] !== undefined)
next = temp[this];
else {
if (trim(nextNamePart) == '')
next = [];
else
next = {};
}
}
if (trim(this) == '') {
temp.push(next);
} else
temp[this] = next;
temp = next;
});
}
});
return o;
}
我最近遇到了同样的问题,并推出了这个.toJSONjQuery插件,它将表单转换为具有相同结构的JSON对象。这对于动态生成的表单也特别有用,因为您希望用户在特定位置添加更多字段。
重点是你可能实际上想要构建一个表单,这样它本身就有一个结构,所以让我们假设你想要创建一个用户在城镇中插入他最喜欢的位置的表单:你可以想象这个表单代表一个<places></places>XML元素,包含用户喜欢的位置列表,因此是<place>列表</place>元素,每个元素包含例如<name></name>元素,一个<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>标记是根,但是我们有一个<place>元素,它是一个容器,而不是数据元素本身,所以我们不能为它使用输入标记。
这里是<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插件,有人在这个CodeReview线程中帮助优化了这个插件,看起来像这样:
$.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(甚至是单选和复选框),您只需调用
$.post('script.php',('form').toJSO(), ...);
我知道有很多方法可以将表单转换为JSON对象,当然.serialize()和.serializeArray()在大多数情况下都非常有效,而且主要是为了使用,但我认为将表单编写为具有有意义名称的XML结构并将其转换为格式良好的JSON对象的整个想法值得一试,如果您需要检索动态生成的表单数据,那么可以添加同名输入标记而不必担心这一事实也非常有用。
我希望这对某人有所帮助!
对于语义ui/formantic ui,有一个内置的行为get值:
const fields = $("#myForm.ui.form").form('get values');
const jsonStr = JSON.stringify(fields);
看见https://fomantic-ui.com/behaviors/form.html#/settings
get-values(标识符)返回与标识符数组匹配的元素值的对象。如果未通过IDS,将返回所有字段
所以我使用了公认的答案,发现了一个主要缺陷。它不支持以下输入数组:
<input type="checkbox" name="array[]" value="1"/>
<input type="checkbox" name="array[]" value="2"/>
<input type="checkbox" name="array[]" value="3"/>
这一小改动应该可以解决以下问题:
function objectifyForm(inp){
var rObject = {};
for (var i = 0; i < inp.length; i++){
if(inp[i]['name'].substr(inp[i]['name'].length - 2) == "[]"){
var tmp = inp[i]['name'].substr(0, inp[i]['name'].length-2);
if(Array.isArray(rObject[tmp])){
rObject[tmp].push(inp[i]['value']);
} else{
rObject[tmp] = [];
rObject[tmp].push(inp[i]['value']);
}
} else{
rObject[inp[i]['name']] = inp[i]['value'];
}
}
return rObject;
}
记住将$(this).serializeArray()的输出传递给它;否则它不会起作用。