【问题标题】:How to create a nested object (JSON) of a form input values based on the input name in vanilla JavaScript?如何根据 vanilla JavaScript 中的输入名称创建表单输入值的嵌套对象 (JSON)?
【发布时间】:2017-12-08 12:57:49
【问题描述】:

//让我们说表格如下所示

 <form id="myform">
      <input name="foo" value="parent"/>
      <input name="foo.cat.bar" value="child1"/>
      <input name="foo.cat.biz" value="child2"/>
      <input name="foo.cat.biz.dog.bar" value="child3"/>
  </form>

// 我希望基于输入名称 attr 的 JSON 格式的输出是这样的 //(这只是一个示例,需要通用答案和最佳方法)

{
    "foo": "parent",
    "foo.cat": {
        "bar": "child1",
        "biz": "child2",
        "foo.cat.biz.dog": {
            "bar": "child3"
        }
    }
}

【问题讨论】:

  • 到目前为止你自己尝试过什么?
  • 如果您在提交表单时想要对象,您可以从“名称”字段中创建一个嵌套对象,并以点分隔来嵌套数据。
  • 或者你应该使用一个框架来实现这个
  • 您想要的输出似乎有点不一致。为什么最后一个嵌套对象附加到属性 "foo.cat.biz.dog" 而不是 "biz.dog"
  • 我正在考虑使用多个对象,然后根据条件(如果名称与倒数第二个元素相同),将值分配给新对象。最后,将物体推入彼此。然而,这是一种非常硬的代码方法,听起来不像是好的编程。我现在想不出别的。

标签: javascript


【解决方案1】:

您可以使用 jQuery 并像这样使用 serializeArray() 方法var jsonData = $('form').serializeArray();:

它与您的示例对象不匹配,但可以满足您的问题。

一旦你拥有了一个数组中的字段,你就可以随心所欲地操作你的对象。我无法完全遵循您如何从表单名称属性中获得该对象的逻辑,因此我什至无法尝试映射它。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="myform">
      <input name="foo" value="parent"/>
      <input name="foo.cat.bar" value="child1"/>
      <input name="foo.cat.biz" value="child2"/>
      <input name="foo.cat.biz.dog.bar" value="child3"/>
  </form>
  <input id='btnSerialize' value='Serialize' type='button' onclick='serializeForm()' />
  <div id='result'></div>
  <script>
 
  function serializeForm()
  {
    var jsonData = $('form').serializeArray();
    var jsonString = JSON.stringify(jsonData);
    $('#result').html(jsonString);
  }

  </script>

如果您更改表单名称以便拥有比普通 javascript 更有效的逻辑结构:

/*
{
  "foo": {
    "bar": "parent",
    "biz": "parent",
    "cat": {
      "bar": "child2achild2a,child2b",
      "biz": {
        "dog": {
          "bar": "child3"
        }
      }
    }
  }
}
*/
<form id="myform">
  <input name="foo.bar" value="parent" />
  <input name="foo.biz" value="parent" />
  <input name="foo.cat.bar" value="child2a" />
  <input name="foo.cat.bar" value="child2b" />
  <input name="foo.cat.biz.dog.bar" value="child3" />
</form>
<script>
  function serialize() {
    var elements = document.querySelectorAll('#myform input');
    var data = {};
    for (var i = 0; i < elements.length; i++) {
      var el = elements[i];
      var val = el.value;
      if (!val) val = "";
      var fullName = el.getAttribute("name");
      if (!fullName) continue;
      var fullNameParts = fullName.split('.');
      var prefix = '';
      var stack = data;
      for (var k = 0; k < fullNameParts.length - 1; k++) {
        prefix = fullNameParts[k];
        if (!stack[prefix]) {
          stack[prefix] = {};
        }
        stack = stack[prefix];
      }
      prefix = fullNameParts[fullNameParts.length - 1];
      if (stack[prefix]) {

        var newVal = stack[prefix] + ',' + val;
        stack[prefix] += newVal;
      } else {
        stack[prefix] = val;
      }
    }
    console.log(data);

  }
</script>
<input type="button" value="go" onclick="serialize()" />
<p><br /></p>
<p><br /></p>

【讨论】:

  • “它与您的样本不匹配,但它符合您的问题” - 样本构成问题的一部分,也是问题的前几个词“如何创建 nested 对象”,不仅“jQuery”标签没有出现,而且标题明确表示“vanilla JavaScript”。
  • 明白,但正如我所说,我什至无法遵循您将如何从表单输入字段中获取该对象的逻辑。一旦你有了一个数组,你可以随意映射它。
  • 感谢您的解决方案。但是,我正在寻找一种普通的 JavaScript 方法而不是库。
  • 在一次采访中被问到。我举了一个例子。本质是根据输入名称创建表单输入值的嵌套对象。急于否决一个问题。
  • 添加了香草实现,但您的表单元素名称对于您的要求无效。面试问题的重点可能会深入了解您的思维过程以及您将如何获得解决方案。
【解决方案2】:

给你。我在 cmets 中包含了一个解释...

function getFormData() {
    /* return nested array combined
       into groups of two. See question @ 
       https://stackoverflow.com/a/31352555/4746328 */
    function groupIntoPairs(arr) {
        var temp = arr.slice();
        var out = [];

        while (temp.length) {
            out.push(temp.splice(0,2));
        }

        return out;
    }

    /* create a storage object */
    var data = {},
    /* get 'input' elements as an array */
    inputs = [].slice.call(document.getElementById('myform').querySelectorAll('input')),
    /* additional variables */
    name, hold, splits, L, dKey;

    /* loop through input elements */
    inputs.forEach(function(n) {
        name = n.name;

        /* for holding key strings */
        hold = '';

        /* split the 'name' at '.'
           and group into pairs */ 
        splits = groupIntoPairs( name.split('.') );

        /* index of last item in 'splits' */
        L = splits.length - 1;

        /* if 'splits' has only one
           item add the name-value pair
           to 'data' straight away */
        if (L === 0) {
            data[name] = n.value;
        } else {
            /* loop 'splits' to create keys */
            splits.forEach(function(x, i) {
                /* combine key strings until
                   last item in 'splits' */
                if (i !== L) hold += '.' + x.join('.');
            });

            /* define the key */
            dKey = hold.slice(1);

            /* create 'data[dKey]' Object if
               it doesn't exist or use it
               again if it does */
            data[dKey] = data[dKey] || {};

            /* add last item in 'splits' as 
               key for 'data[dKey]' and 
               assign current n.value */
            data[dKey][splits[L][0]] = n.value;                
        }
    });
    /* return 'data' object */
    return data;
}

console.log('data:', JSON.stringify(getFormData(), null, 4));
/* => data: {
    "foo": "parent",
    "foo.cat": {
        "bar": "child1",
        "biz": "child2"
    },
    "foo.cat.biz.dog": {
        "bar": "child3"
    }
}
*/

希望有所帮助。

【讨论】:

  • 如果输入共享相同的名称(在复选框列表和单选按钮中很常见),这将不起作用。一个值会丢失。
  • @AlexanderHiggins 确实,但它适用于问题中提供的特定格式,并且示例返回请求的 JSON 输出。 ;)
猜你喜欢
  • 2019-11-05
  • 2022-01-25
  • 2019-11-13
  • 2013-06-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多