【问题标题】:HTML form with hierarchical fields to JSON object具有到 JSON 对象的分层字段的 HTML 表单
【发布时间】:2018-09-13 08:03:47
【问题描述】:

例如。我们有这个表格:

<form id="to-object">
<input name="data[zero_key]" value="It`s too simple" />
<input name="data[first_key][value]" value="It`s simple too" />
<input name="data[second_key][]" value="Push me" />
<input name="data[second_key][]" value="Push me please" />
<input name="data[next_key][0][type]" value="I don`t wanna be object with key 0. " />
<input name="data[next_key][0][number]" value="I`m array!!!" />
</form>

所以问题是:如何正确序列化这个表单并得到这个结果:

    {
  "zero_key": "It`s too simple",
  "first_key": {
    "value": "It`s simple too"
  },
  "second_key": [
    "Push me",
    "Push me please",
  ],
  "next_key": [
    {
      "type": "I don`t wanna be object with key 0.",
      "number": "I`m array!!!"
    },

  ],

}

我有什么:

(function($) {
    $.fn.convertFormDataToObject = function(){

        var extractFieldNames = function(fieldName, expression, keepFirstElement)
        {

            expression = expression || /([^\]\[]+)/g;
            keepFirstElement = keepFirstElement || false;

            var elements = [];

            while((searchResult = expression.exec(fieldName)))
            {
                    elements.push(searchResult[0]);

            }

            if (!keepFirstElement && elements.length > 0) elements.shift();

            return elements;
        }

        var attachProperties = function(target, properties, value)
        {

            var currentTarget = target;
            var propertiesNum = properties.length;
            var lastIndex = propertiesNum - 1;
            for (var i = 0; i < propertiesNum; ++i)

            {
                currentProperty = properties[i];

                if(currentProperty == ""){
                    var intKey = Math.floor(Math.random() * (99 - 1)) + 1;
                    currentProperty = intKey.toString();
                } else if(!isNaN(currentProperty)) {
                    currentProperty = [parseInt(currentProperty)];
                } else {
                    currentProperty = properties[i];
                }

                if (currentTarget[currentProperty] === undefined)
                {
                    currentTarget[currentProperty] = (i === lastIndex) ? value : {};                    }
                                    currentTarget = currentTarget[currentProperty];
            }
        }

        var convertFormDataToObject = function(form) {
                var currentField = null;
            var currentProperties = null;
                // result of this function
            var data = {};
            // get array of fields that exist in this form
            var fields = form.serializeArray();
            for (var i = 0; i < fields.length; ++i)
            { currentField = fields[i];
                // extract field names
                currentProperties = extractFieldNames(currentField.name);
                // add new fields to our data object
                attachProperties(data, currentProperties, currentField.value);
            }
            return data;
        }
        var form = $(this);
        var data = convertFormDataToObject(form);
        return data;
    };
})(jQuery);

正如您在此示例中看到的,我正在使用随机 int 生成器来解决 [] 之间的空白问题。这是一个问题,但不是关键。关键是我无法解决数组生成的问题。此脚本将 name 属性中的所有键添加为对象的键,它给出了错误的对象。代替带有对象的数组,它提供带有键“0”、“1”等的对象。例如"0":{},"1":{} 而不是[{},{}]

如果您知道如何使用 JS 修复它,我将非常感谢您的帮助!

【问题讨论】:

  • 判断值是数组还是对象还是字符串的逻辑应该是什么。
  • 如果 name 是这样的 data[cars][] 我知道应该将值推送到名为汽车的数组中。例如{ "cars":["AUDI","BMW"] }.
  • 如果name 是这样的data[cars][][bmw][model],输出应该是这样的{"cars":[{"bmw":{"model":"x10"}}]}。对于具有此结构的name,结果相同:data[cars][0][bmw][model]。 @NenadVracar,感谢您的帮助!

标签: javascript jquery arrays json javascript-objects


【解决方案1】:

您可以大大降低代码的复杂性,试试这样:

const finalObj = [...document.querySelector('form').children].reduce((objSoFar, child) => {
  const value = child.value;
  let allKeys = child.name.slice(4).split('][');
  allKeys[0] = allKeys[0].slice(1);
  const lastKeyIndex = allKeys.length - 1;
  allKeys[lastKeyIndex] = allKeys[lastKeyIndex].slice(0, allKeys[lastKeyIndex].length - 1);
  // now: eg "data[next_key][0][number]" has allKeys ["next_key", "0", "number"]
  
  let refObj = objSoFar;
  while (allKeys.length > 1){
    if (!refObj[allKeys[0]]) {
      if (allKeys[1] === '' || /^\d+$/.test(allKeys[1])) refObj[allKeys[0]] = [];
      else refObj[allKeys[0]] = {};
    }
    refObj = refObj[allKeys[0]];
    allKeys = allKeys.slice(1);
  }
  
  const lastKey = allKeys[0];
  if (lastKey === '') refObj.push(value);
  else refObj[lastKey] = value;
  return objSoFar;
}, {});
console.log(finalObj);

const desiredSerializedResult = '{"zero_key":"It`s too simple","first_key":{"value":"It`s simple too"},"second_key":["Push me","Push me please"],"next_key":[{"type":"I don`t wanna be object with key 0.","number":"I`m array!!!"}]}';
if (JSON.stringify(finalObj) === desiredSerializedResult) console.log('Matches desiredSerializedResult');
<form id="to-object">
  <input name="data[zero_key]" value="It`s too simple" />
  <input name="data[first_key][value]" value="It`s simple too" />
  <input name="data[second_key][]" value="Push me" />
  <input name="data[second_key][]" value="Push me please" />
  <input name="data[next_key][0][type]" value="I don`t wanna be object with key 0." />
  <input name="data[next_key][0][number]" value="I`m array!!!" />
</form>

(但这似乎真的是一个 XY 问题 - 几乎可以肯定,有比需要这样的逻辑更好的方法来设置您的应用程序)

【讨论】:

  • 非常感谢您的帮助!但是如何修复这部分"next_key": { "0": { "type": "I don't wanna be object with key 0. ", "number": "I'm array!!!" }
  • 修好了,只测试看看下一行的key是不是数字(除了空字符串)来决定是推数组还是对象
  • 你是天才!!! ))) 现在唯一的问题是让它与“select”、多个“select”和“textarea”元素一起工作......我已经将选择器更改为document.querySelector('form').getElementsByTagName("input","select", "textarea") 并添加了额外的验证(例如:if(child.tagName === 'SELECT') {const value = child.options[child.selectedIndex].value;})但是它不起作用...也许我需要在另一个地方进行验证?
猜你喜欢
  • 2014-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-28
  • 2015-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多