我正在尝试用 vanilla JS 编写一个
form_to_json
序列化函数以创建有效的 JSON。
但我坚持解析多个输入,所有输入都具有相同的名称。
这是我当前的功能,请注意我卡住的地方的评论。
// gather form elements and serialize inputs
function form_to_json(form_id) {
console.log(`Getting form with ID ${form_id}`);
let obj_form = document.getElementById(form_id);
// Create an object
var obj = {};
// Loop through each field in the form
Array.prototype.slice.call(obj_form.elements).forEach(function(field) {
// Skip some fields we don't need
if (!field.name || field.disabled || ['file', 'reset', 'submit', 'button'].indexOf(field.type) > -1) return;
// Handle multi-select fields
if (field.type === 'select-multiple') {
// Create an array of selected values
var options = [];
// Loop through the options and add selected ones
Array.prototype.slice.call(field.options).forEach(function(option) {
if (!option.selected) return;
options.push(option.value);
});
// If there are any selection options, add them to the object
if (options.length) {
obj[field.name] = options;
}
return;
}
// If it's a checkbox or radio button and it's not checked, skip it
if (['checkbox', 'radio'].indexOf(field.type) > -1 && !field.checked) return;
console.log(`${field.name}: ${field.value}`);
// Add the value to the object
if (field.name in obj) {
// NOT SURE WHAT TO DO HERE
obj[field.name].push(field.value);
} else {
obj[field.name] = field.value;
}
});
// Return the object
return obj;
}
这是一个屏幕截图,显示了最终用户如何创建输入的视觉效果。
使用我当前的函数代码,显然我只能获取每个冗余字段名称的最后一组值。
前端允许用户动态添加“条件”行(基本上是这 3 个输入的集合,每行之间的名称都相同)。
我的尝试是检查该密钥是否已存在于对象中,如果存在,/做某事/但我无法弄清楚那是什么。
您可以修改
if
语句,将现有值转换为数组(如果它还不是数组)。 if
看起来像这样:
// Add the value to the object
if (field.name in obj) {
if (!Array.isArray(obj[field.name])) {
obj[field.name] = [obj[field.name]];
}
obj[field.name].push(field.value);
} else {
obj[field.name] = field.value;
}
下面是修改后代码的工作示例:
const form = document.getElementById('myform');
form.addEventListener('submit', function (e) {
e.preventDefault();
const serialized = form_to_json('myform');
console.log(serialized);
});
// gather form elements and serialize inputs
function form_to_json(form_id) {
console.log(`Getting form with ID ${form_id}`);
let obj_form = document.getElementById(form_id);
// Create an object
var obj = {};
// Loop through each field in the form
Array.prototype.slice.call(obj_form.elements).forEach(function (field) {
// Skip some fields we don't need
if (!field.name || field.disabled || ['file', 'reset', 'submit', 'button'].indexOf(field.type) > -1) return;
// Handle multi-select fields
if (field.type === 'select-multiple') {
// Create an array of selected values
var options = [];
// Loop through the options and add selected ones
Array.prototype.slice.call(field.options).forEach(function (option) {
if (!option.selected) return;
options.push(option.value);
});
// If there are any selection options, add them to the object
if (options.length) {
obj[field.name] = options;
}
return;
}
// If it's a checkbox or radio button and it's not checked, skip it
if (['checkbox', 'radio'].indexOf(field.type) > -1 && !field.checked) return;
console.log(`${field.name}: ${field.value}`);
// Add the value to the object
if (field.name in obj) {
if (!Array.isArray(obj[field.name])) {
obj[field.name] = [obj[field.name]];
}
obj[field.name].push(field.value);
} else {
obj[field.name] = field.value;
}
});
// Return the object
return obj;
}
<form id='myform'>
<input name='crit' />
<input name='crit' />
<input name='crit' />
<input name='otherfied' />
<input type='submit' value='submit' />
</form>
不管OP实际上不想创建
JSON
(这是一种基于字符串的数据格式),而是想以自定义方式创建统一的表单数据,任何解决方案首先应该基于 FormData
Web API、表单数据的 entries
列表和单个 reduce
任务的使用。
FormData
实例提供对表单的所有相关控件/元素值的访问,实际上已经按照OP正在寻找的方式进行了过滤,这只留下了将同名字段名称的值收集到数组中的任务,从而将条目数组(键值对)减少为基于对象的数据结构。
整个代码变得更短并且可读性更好。
function getUnifiedFormData(elmForm) {
return [
...new FormData(elmForm).entries()
]
.reduce((result, [key, value]) => {
if (Object.hasOwn(result, key)) {
if (Array.isArray(result[key])) {
result[key].push(value);
} else {
result[key] = [result[key], value];
}
} else {
result[key] = value;
}
return result;
}, {});
}
document
.forms['my-form']
.addEventListener('submit', evt => {
evt.preventDefault();
const data = getUnifiedFormData(evt.currentTarget);
console.clear();
console.log({ data });
});
body { margin: 0; }
form { width: 29%; }
label { float: left; margin: 2px 4px; }
select { clear: left; margin: 2px 0; padding: 2px 10px; }
[type="text"] { margin: 4px 0; }
[type="text"], select, label > span { display: block; }
.as-console-wrapper { left: auto!important; width: 70%; min-height: 100%; }
<form id='my-form'>
<input type="text" name='text-values' />
<input type="text" name='text-values' />
<input type="text" name='text-values' />
<label>
<span>red</span>
<input type="checkbox" name="selected-colors" value="red" />
</label>
<label>
<span>yellow</span>
<input type="checkbox" name="selected-colors" value="yellow" />
</label>
<label>
<span>green</span>
<input type="checkbox" name="selected-colors" value="green" />
</label>
<select name="picked-fruits" multiple>
<option>Apple</option>
<option>Orange</option>
<option>Banana</option>
</select>
<input type="text" name='other' value="other value" disabled />
<input type='submit' name="submit" value="submit" />
<input type='reset' name="reset" value="reset" />
<input type='button' name="button" value="button" />
</form>