提交两个表单需要一个按钮

59

我有两个HTML表单,一个使用PHP在输入数据后将其提交到数据库,另一个将用户引导到PayPal付款页面。我的问题是用户必须提交两个表单,但我不希望他们这样做。有没有办法使用一个提交按钮来处理两个表单?

(欢迎使用JavaScript)

7个回答

48
表单提交会导致页面跳转到表单的“action”位置。因此,您不能以传统方式提交两个表单。如果您尝试使用JavaScript依次调用每个表单的“form.submit()”,则除了最后一个提交之外,每个请求都将被中止。因此,您需要通过JavaScript异步提交第一个表单:
var f = document.forms.updateDB;
var postData = [];
for (var i = 0; i < f.elements.length; i++) {
    postData.push(encodeURIComponent(f.elements[i].name) + "=" +
        encodeURIComponent(f.elements[i].value));
}
var xhr = new XMLHttpRequest();
xhr.open("POST", "mypage.php", true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(postData.join("&"));

document.forms.payPal.submit();

2023年更新

原始答案仍然完美地运行,但这里是使用fetch()和现代语法的更新:

function submitBothForms() {
    const { updateDB, payPal } = document.forms;
    fetch(updateDB.action, {
        method: updateDB.method,
        headers: { "content-type": updateDB.enctype },
        body: new FormData(updateDB),
    });

    payPal.submit();
}
请注意,虽然通常您会await调用fetch,但我们在这里不这样做,因为由于您想同时提交两个表单,所以您不必关心updateDB表单是否成功。 因此,延迟提交payPal表单没有意义。 如果这不是您想要的,您可以序列化调用,并逐个提交表单,添加一些错误处理:
async function submitBothForms() {
    const { updateDB, payPal } = document.forms;
    const res = await fetch(updateDB.action, {
        method: updateDB.method,
        headers: { "content-type": updateDB.enctype },
        body: new FormData(updateDB),
    });
    if (!res.ok) {
        const err = new Error(`DB Update Failed! Status: ${res.status}`);
        const isJSON = res.headers.get("content-type") == "application/json";
        err.body = await (isJSON ? res.json() : res.text());
        throw err;
    }

    payPal.submit();
}

这样,如果第一个表单不成功,就会抛出错误,防止提交第二个表单。我会把处理错误和显示错误消息的工作交给您。


1
好的回答,但取决于情况和表单的提交方式,第一个表单的提交可能会阻止第二个表单的提交(例如,在一个表单上使用submit事件调用另一个表单的submit()将仅在Firefox中提交第一个表单)。 - RobG
1
在 xhr 对象完成之前,不应提交第二个表单。 - Katie Kilian

47

你应该可以使用JavaScript实现这个:

<input type="button" value="Click Me!" onclick="submitForms()" />

如果您的表单有ID:

submitForms = function(){
    document.getElementById("form1").submit();
    document.getElementById("form2").submit();
}
如果你的表单没有ID但是有名称:
submitForms = function(){
    document.forms["form1"].submit();
    document.forms["form2"].submit();
}

1
这与时间有关吗?设置提交之间的短超时时间可能会解决问题吗? - James Johnson
22
这是完全错误的(至少在Chrome和IE9中)!请查看我下面的回答。 - Jonas Byström
像支付网站一样吗? - Hitesh
我不确定为什么这个答案被选为正确答案。这是完全错误的。提交一个表单将重定向页面,第二个表单将永远不会提交。 - Rohan
答案中最错误的是你的自信心 :P - Agamemnon Katradis
显示剩余3条评论

14

您可以使用 AJAX 提交第一个表单,否则一个表单的提交将阻止另一个表单的提交。


10

在Chrome和IE9(及其他所有浏览器)中,只有后一个请求将生成套接字连接,第一个请求将被丢弃。(浏览器检测到这两个请求都在你上面的JavaScript“时间片”内发送,并丢弃除最后一个请求外的所有请求。)

如果您改为使用某些事件回调来执行第二次提交(但在接收到回复之前),则第一个请求的套接字将被取消。这绝对不是推荐的方法,因为在这种情况下,服务器可能已经处理了您的第一个请求,但您永远不会确定。

我建议您使用/生成一个单一的请求,可以在服务器端进行事务处理。


使用 Promises 或 Deferred 对象也是一个有价值的替代方案。 - Kamafeather

8

目前选择的最佳答案太模糊了,不够可靠。

我觉得这是一个相当安全的方法:

(JavaScript:使用jQuery使其更简单)

$('#form1').submit(doubleSubmit);

function doubleSubmit(e1) {
    e1.preventDefault();
    e1.stopPropagation();
    var post_form1 = $.post($(this).action, $(this).serialize());

    post_form1.done(function(result) {
            // would be nice to show some feedback about the first result here
            $('#form2').submit();
        });
};

在不更改页面的情况下先提交第一个表单,等待处理完成后再提交第二个表单。第二个提交将更改页面,但您可能也希望为第二个表单编写一些类似的代码,以获得第二个延迟对象 (post_form2?)。

尽管如此,我并没有测试过这段代码。


为什么要点踩?如果我写错了什么,留下评论会更好地得到赞赏。 - Kamafeather
为什么你同时使用了 e1.preventDefault();e1.stopPropagation();?我猜其中一个就足够了。 顺便说一下,我没有给你的页面投反对票。只是我进来了,有些疑问。 - dev_khan
1
@dev_khan它们提供不同的功能,所以没有一个会足够。preventDefault肯定是必需的,为了防止默认的submit并掌握该事件将发生什么。相反,stopPropagation取决于用例,在事件不应从外部元素捕获的情况下(无法回忆,但可能去年我在即兴编码时放置它* -只是为了安全起见)。不用担心,我没有认为你投票反对(为什么我得到它仍然是个谜),但感谢您的指定。 - Kamafeather

-2
如果你想使用一个按钮提交两个表单,你需要这样做: 1- 使用 setTimeout() 2- 允许显示弹出窗口
<script>
function myFunction() {
setTimeout(function(){ document.getElementById("form1").submit();}, 3000);   
setTimeout(function(){ document.getElementById("form2").submit();}, 6000);   
}
</script>
<form  target="_blank" id="form1">
<input type="text">
<input type="submit">
</form>
<form target="_blank" id="form2">
<input type="text">
<input type="submit">
</form>

JavaScript不能同时提交两个表单,我们使用一个按钮提交两个表单,但不是同时提交,而是在几秒钟后提交。

编辑:当我们使用此代码时,浏览器不允许弹出窗口。
如果您像我一样将此代码用于软件,请设置浏览器以显示弹出窗口,但如果您将其用于设计网站,则浏览器是一个障碍,代码无法运行。


2
等待并不能告知第一次提交是否成功(根据工作流程,第二个表单可能需要防止提交),也不能保证两个请求的顺序处理(例如,如果PayPal交易失败,我应该将交易存储在数据库中吗?)请看看我写的替代答案;我试图提供更多的工作流程和结果控制。 - Kamafeather

-3
如果您有一个常规的提交按钮,您可以为其添加一个onclick事件,该事件执行以下操作:
document.getElementById('otherForm').submit();

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