jQuery serializeArray不包括被点击的提交按钮。

67
我有一个表单,其中有两个按钮。一个用于保存记录,另一个用于取消保存过程。我正在使用 rails.js(一种常见的 AJAX/jQuery 插件,对于那些不知道的人来说)javascript 文件,它与 jQuery 一起使用无侵入式 javascript/ajax 调用。当我通过ajax发送表单数据时,我希望所点击的按钮的名称和值随其他数据一起提交,以便我可以根据所点击的按钮做出决定。 rails.js 文件中的方法使用 .serializeArray() 将表单数据发送到服务器。问题是这不包括我点击的按钮的名称/值对。jQuery 的网站指出他们故意这样做(尽管我认为他们应该):
.serializeArray() 方法使用标准的 W3C 规则 成功的控件 来确定哪些元素应该包括;特别是元素不能被禁用,必须包含一个名称属性。由于表单没有使用按钮提交,因此不会序列化任何提交按钮值。”
他们怎么能假设表单没有使用按钮提交呢?我认为这没有意义并且是错误的假设。
根据 W3C 规则,用于提交表单的按钮被视为一个成功的控件。
由于 jQuery 的开发人员已经故意这样做,我可以假设是否有另一种方法可以在序列化中不排除已激活的按钮?

编辑:这里是我的表单可能看起来的快速示例...

<!DOCTYPE html5>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
  $(document).ready(function() {
    $('#form').submit(function(e) {
      // put your breakpoint here to look at e
      var x = 0;
    });
  });
</script>
</head>
<body>
  <form id="form">
    <input name="name" type="text"><br/>
    <input name="commit" type="submit" value="Save"/>
    <input name="commit" type="submit" value="Cancel"/>
  </form>
</body>

5
如果其他人也遇到了这个问题,<button>标签也存在同样的问题。 - DickieBoy
6个回答

76

有没有一种方法可以在序列化时不排除已激活的按钮?

没有,该行为基于<form>submit事件,而不是按钮的事件,例如按下Enter键或使用JavaScript中的.submit()。你混淆了两个概念: .serialize().serializeArray() 可能与按钮单击无关 - 它们只是完全独立的事件,它们并不相互关联。 这些方法位于更高的级别上:您可以随时以任何原因对表单(或其子集)进行序列化。

但如果您从按钮提交表单,则可以像正常表单提交一样添加提交名称/值对:

$("#mySubmit").click(function() {
  var formData = $(this).closest('form').serializeArray();
  formData.push({ name: this.name, value: this.value });
  //now use formData, it includes the submit button
});

@DJTripleThreat - 我对他们的代码不是很熟悉,也许可以在外部替换事件处理程序吗?如果您能发布它,我会看一下。 - Nick Craver
@Nick - 请查看 gh 上的文件:http://github.com/rails/jquery-ujs/blob/master/src/rails.js。请查看第34行和第76行上的处理程序。有办法在 .submit(function(e){}) 传递的 event 对象中找出点击了哪个按钮吗? - aarona
@DJTripleThreat - 你可以使用 e.target 并将其传递给 callRemote,这可能是最简单的方法,只需接受一个事件参数,内部使用 e.target,你可以检查 if($(e.target).is(":submit"))... - Nick Craver
@DJTripleThreat - 对于混淆感到抱歉,您还需要将click处理程序附加到提交按钮本身,就像这样:$('form[data-remote] :submit').live('submit', function (e) { $(this.form).callRemote(e); return false; }); - Nick Craver
@DJTripleThreat 我通过在提交处理程序中附加 document.activeElementnamevalue 来处理这个问题。我认为它不是完全跨浏览器兼容的,但作为更大抽象的一部分,可能会很好地处理它。 - Tim
显示剩余3条评论

13

这里是一个相当简洁的解决办法:

<form>
    <input type="hidden" name="stuff" value="">
    <button type="submit" onclick="this.form.stuff.value=this.value" value="reset">reset</button>
    <button type="submit" onclick="this.form.stuff.value=this.value" value="delete">delete</button>
</form>

8
我使用以下代码片段,基本上是添加一个与名称相同的隐藏元素。
 var form = $("form");
 $(":submit",form).click(function(){
            if($(this).attr('name')) {
                $(form).append(
                    $("<input type='hidden'>").attr( { 
                        name: $(this).attr('name'), 
                        value: $(this).attr('value') })
                );
            }
        });

 $(form).submit(function(){
     console.log($(this).serializeArray());
 });

3
这个解决方案是“通用”的,它将处理您所有的输入提交,并在提交时将每个提交作为表单变量传递。
$(document).ready(function(){
    $('input:submit').each(function(){
        $(this).click(function(){
            var formData = $(this).closest('form').serializeArray();
            formData.push({ name: $(this).attr('name'), value: $(this).val() });
        });
    });
});

4
不需要使用 each 方法,可以直接在代表所有输入元素的 jQuery 对象上调用 click 方法。 - SpoonMeiser

1
    var form = button.closest('form');
    var serialize = form.serialize();

    if (button.attr('name') !== undefined) {
        serialize += '&'+button.attr('name')+'=';
    }

1
有点晚了,但是如果你不想给表单上的每个按钮绑定一个事件,你可以包含这段代码:
$form.on('submit', function (e) {

    let formData = $(this).serializeArray();

    if (
        e.originalEvent
        && undefined !== e.originalEvent.submitter
        && undefined !== e.originalEvent.submitter.name
        && typeof e.originalEvent.submitter.name == "string"
        && e.originalEvent.submitter.name.length >= 1
        && undefined !== e.originalEvent.submitter.value
    ) {
        formData.push({
            name: e.originalEvent.submitter.name,
            value: e.originalEvent.submitter.value,
        });
    }

    // ...

});

在您的表单上,任何具有至少1个字符长的字符串名称和定义值的提交按钮都将包含在对象数组formData中。

你值得一块饼干 - undefined

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