带有分层字段的HTML表单到JSON对象

时间:2018-04-03 21:37:10

标签: javascript jquery arrays json javascript-objects

例如。我们有这样的形式:

<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属性中的所有键添加为对象的键,并提供错误的对象。它不是带有对象的数组,而是为对象提供键&#34; 0&#34;,&#34; 1&#34;例如"0":{},"1":{}而不是[{},{}]

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

1 个答案:

答案 0 :(得分: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问题 - 几乎可以肯定,设置应用程序的方式比需要这样的逻辑的方法更好)