当存在多个同名的表单元素时,如何创建基于对象的表单数据?

问题描述 投票:0回答:2

我正在尝试用 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 个输入的集合,每行之间的名称都相同)。

我的尝试是检查该密钥是否已存在于对象中,如果存在,/做某事/但我无法弄清楚那是什么。

javascript arrays reduce key-value form-data
2个回答
1
投票

您可以修改

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>


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.