jQuery - serializeArray()无法获取已选中复选框的值

6

我在表单中有一个复选框,它作为一个标记。

为了实现它,我添加了一个隐藏的输入元素,这样如果复选框未被选中,仍然会保存一些内容。

<form action="">
    ...
        <input type="hidden" name="foo" value="no" />
        <input type="checkbox" name="foo" value="yes">
    ...
</form>

我遇到的问题是,在我

  1. 勾选复选框
  2. 然后在表单上运行 jQuery.serializeArray()

foo 元素设置的值为 "no"。

Object { name="foo", value="no"}

serializeArray()应该模拟浏览器行为吗?如果是,如果复选框被选中,它不应该返回“是”吗?

我正在使用jQuery v1.10.2


2
尝试为隐藏类型和复选框类型的输入使用不同的名称。 - dotnetstep
@dotnetstep 这些名称相同是有意的,因为这只是我想要传递的一个值。 - developarvin
6个回答

5
在具有相同名称的多个输入的表单上使用serializeArray会返回每个元素(如果已选中)超过一个对象。这意味着以下HTML将返回以下对象。因此,所需数据可用并且可用。因此,我假设您正在尝试操纵数据以成为1对象,或者正在将其发布到仅考虑具有该键的第一个值的服务器。您只需要确保任何checkbox元素具有优先权。
返回的对象:
[
    {
        name:"foo",
        value:"no"
    },
    {
        name:"foo2",
        value:"no"
    },
    {
        name:"foo2",
        value:"yes"
    }
] 

HTML:

<form>
    <input type="hidden" name="foo" value="no" />
    <input type="checkbox" name="foo" value="yes" />

    <input type="hidden" name="foo2" value="no" />
    <input type="checkbox" name="foo2" value="yes" checked />
</form>

JS:

console.log($('form').serializeArray());

演示

另一种方法是去除隐藏字段,在提交表单之前遍历每个未选中的复选框,并检查serializeArray中是否有相同名称的数据。如果没有,就将其添加为 off

$('#submit').on('click', function(){
    var arr = $('form').serializeArray(),
        names = (function(){
            var n = [],
                l = arr.length - 1;
            for(; l>=0; l--){
                n.push(arr[l].name);
            }

            return n;
        })();

    $('input[type="checkbox"]:not(:checked)').each(function(){
        if($.inArray(this.name, names) === -1){
            arr.push({name: this.name, value: 'off'});
        }
    });

    console.log(arr);
});

DEMO


1
那么您的意思是,serializeArray()无法决定提交哪个值,而不像没有JS的正常表单提交一样? - developarvin
1
不,当数据通过$.post('url', $('form').serializeArray());发送时,它会同时发送这两个数据。我只是展示了这两个数据都被记录并且都通过ajax被发送。这意味着你的服务器没有正确读取数据,很可能是因为有两个具有相同名称的元素。我建议你从复选框中删除名称,并在更改时更新隐藏字段以消除混淆。我马上会在我的答案中添加这段代码。 - Adam Merrifield
@arvinsim 我已经更新了我的答案底部,包括另一种方法,完全不使用任何隐藏字段。这将真正有助于消除您和接收此数据的服务器的任何混淆。 - Adam Merrifield

5
简而言之:否。serializeArray方法只返回已选中的复选框。因此,只要它保持未选中状态,它就会被忽略。
但是,如果您选择了复选框,它将直接返回您输入的值。
请访问http://api.jquery.com/serializearray/查看演示。

1

事实: jQuery serializeArray() 不包括未选中的复选框,而我们可能需要将它们发送到服务器(对于单选按钮没有问题)。

解决方案: 创建一个新的序列化

//1. `sel` any collection of `form` and/or `input`, `select`, `textarea` 
//2. we assign value `1` if not exists to radios and checkboxes
// so that the server will receive `1` instead of `on` when checked
//3. we assign empty value to unchecked checkboxes 
function serialize(sel) {
   var arr,
       tmp,
       i,
       $nodes = $(sel);

   // 1. collect form controls
   $nodes = $nodes.map(function(ndx){
      var $n = $(this);

      if($n.is('form'))
         return $n.find('input, select, textarea').get();
      return this;
    });

   // 2. replace empty values of <input>s of type=["checkbox"|"radio"] with 1 
   // or, we end up with "on" when checked
   $nodes.each(function(ndx, el){
      if ((el.nodeName.toUpperCase() == 'INPUT') && ((el.type.toUpperCase() == 'CHECKBOX') || (el.type.toUpperCase() == 'RADIO'))){
         if((el.value === undefined) || (el.value == ''))
            el.value = 1;
      }
   });

   // 3. produce array of objects: {name: "field attribute name", value: "actual field value"}
   arr = $nodes.serializeArray();
   tmp = [];
   for(i = 0; i < arr.length; i++)
      tmp.push(arr[i].name);

   // 4. include unchecked checkboxes
    $nodes.filter('input[type="checkbox"]:not(:checked)').each(function(){
      if(tmp.indexOf(this.name) < 0){
         arr.push({name: this.name, value: ''});
      }
    });

   return arr;
}

我们将空字符串分配给未选中的复选框的原因是,一个被选中的复选框会提交其在 HTML 中设置的值到服务器,而这个值可能是零!!!
因此,空值表示未选中的复选框。

0
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>

<form url="http://application.localdev/api/v1/register" method="post" id="formReg" accept-charset="utf-8">
    <input type="email" placeholder="email" name="email"><br>
    <input type="text" placeholder="firstname" name="firstname"><br>
    <input type="text" placeholder="lastname" name="lastname"><br>
    <input type="number" placeholder="zip_code" name="zip_code"><br>
    <input type="checkbox" name="general" value="true"> general<br>
    <input type="checkbox" name="marketing" value="true"> marketing<br>
    <input type="checkbox" name="survey" value="true"> survey<br>
    <button type="submit">save</button>
</form>

<script>
    $(document).ready(function() {
        $('#formReg').on('submit', function(e){
            // validation code here
                        
            e.preventDefault();


                            
            var values = {};
            $.each($('#formReg').serializeArray(), function(i, field) {
                values[field.name] = field.value;
            });

            $('input[type="checkbox"]:not(:checked)').each(function(){
                if($.inArray(this.name, values) === -1){
                    values[this.name] = $(this).prop('checked')
                }
            });

            console.log(values)
        });
    });
</script>

0

在多个字段中使用相同的名称最好是有问题的,前端系统或后端系统没有标准化的处理方式。

唯一使用相同名称的原因是如果您想传递某种默认值,就像在下面的情况下一样,您正在执行简单的是/否操作。

您想要模拟浏览器的是serialize方法,而不是serializeArray

我将表单添加到页面中--从我的控制台:

JSON.stringify(f.serializeArray());
"[{"name":"foo","value":"no"}]"

无勾选标记

JSON.stringify(f.serialize());
""foo=no""

勾选

JSON.stringify(f.serialize());
""foo=yes&foo=no""

如果您的后端系统混淆了并且选择了错误的值,请反转您的复选框和隐藏元素的顺序。

奇怪的是,我尝试使用serialize(),它得到了与serializeArray()相同的行为。也就是说,即使复选框被选中,它仍然只传递"foo=no"。 - developarvin
当你说“它只是通过了”时,你从哪里得到这个信息的?如果你的后端只显示一个值,那是正常和正确的。 - Jeremy J Starcher
在执行 AJAX 提交的代码之前,我使用了这个 console.info(JSON.stringify(formElement.serialize())); - developarvin

0

serializeArray 不会返回未选中的复选框。我尝试使用以下代码替代 serializeArray

$('input, select, textarea').each(
   function(index){  
       var input = $(this);
       alert('Type: ' + input.attr('type') + 'Name: ' + input.attr('name') + 
       'Value: ' + input.val());
   }
);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接