admin管理员组

文章数量:1291009

EDIT: Please read carefully all the way through the question before you consider answering it. I am not asking about the advisability of using an inline event handler in production code, nor am I asking about the best way to achieve the result promised by the article I reference. This is a question about Javascript semantics and browser implementation details, not about best coding practices.

Sounds like a nightmare, right?

Yet I found some online advice that advocates doing just such a thing to prevent double-submission of a form:

<input type="submit" 
       onclick="this.disabled=true;
                this.value='Sending, please wait...';
                this.form.submit();" />

Leaving aside any discussion of the evils of inline event handlers, the problems I see here are:

  1. The type of the tag is "submit", so submitting its containing form is its default behavior;
  2. The onclick handler explicitly submits the containing form;
  3. The onclick handler doesn't return false to prevent the default behavior (see 1).

Intuitively, I would think that a click on this item would do exactly the opposite of what the article claims -- i.e., submit the form twice, once as a result of the explicit submit() call, and then once more as the unsuppressed default behavior of the "submit"-typed control.

On the other hand, I wrote a tiny PHP script (below) and tried it out with both Firefox and Safari (at the moment my only conveniently available browsers), and it only writes a single log entry per click on the button:

<html>
<head></head>
<body>
<?php
  if (isset($_GET['action']) && $_GET['action'] == 'submit') {
    $s = 'Got form submission at ' . time();
    error_log($s);
    echo $s;
  }
  else {
?>
  <form action="http://localhost/~hephaestus/phptests/submittest.php?action=submit" 
        method="post">
    <input type="submit" 
           onclick="this.disabled=true;
                    this.value='Sending, please wait...';
                    this.form.submit();" />
  </form>
<?php
  }
?>
</body>
</html>

So are these two browsers actually doing the "right" thing (where "right" is defined in some document that I either haven't seen or haven't read closely enough) -- meaning that my analysis of the problems is inplete or wrong?

Or, is my analysis correct -- meaning that the observed single submissions are the result of the browser implementers putting in special-case logic, to save naive coders from themselves?

UPDATE:

In an effort to empirically test out the claim by @sourcecode that the form.submit() method is some sort of "second submit button" on a form, and is thus subject to the rule stated in section 17.13.2 of the HTML4 spec that there can only be one "successful" submit button, I made a few additions to my PHP test script:

<?php
  if (isset($_GET['action']) && $_GET['action'] == 'submit') {
    $s = 'Got form submission at ' . time() . ', tellme = ' . $_POST['tellme'];
    error_log($s);
    echo $s;
  }
  else {
?>
  <form action="http://localhost/~hephaestus/phptests/submittest.php?action=submit" 
        method="post">
    <input type="hidden" id="tellme" name="tellme" value="0" />
    <input type="submit" 
           onclick="this.disabled=true;
                    this.value='Sending, please wait...';
                    this.form.submit();
                    document.getElementById('tellme')=1;" />
  </form>
<?php
  }
?>

In Firefox, this code produces the single error-log entry:

Got form submission at timestamp, tellme = 1

which does suggest that the method-invocation is somehow being superseded by the intrinsic event-driven behavior of the control.

Furthermore, if I include an additional return false; after setting the value of tellme to 1 (thereby preventing the click event from propagating, and thus preventing the intrinsic behavior of the control), the single error-log entry is:

Got form submission at timestamp, tellme = 0

meaning that in this case, the submission was the result of the invocation of this.form.submit().

On the other hand, when I try the same two variations in Safari, each of them gives me the same single error-log entry:

Got form submission at timestamp, tellme = 0

So in the case of Safari, the method invocation always takes precedence over the event-driven submission -- presumably because it happens earlier.

That's. Just. Awesome. :-/

Further update: I got a chance to test this on IE 8.0 on Windows NT 5.1.

IE 8 mirrors the behavior of Safari, i.e., the form.submit() method always takes precedence over the even-driven submit.

Although it's hardly relevant today, I also realized that I have an ancient IE 5.22 on an even more ancient PowerPC iMac running OS X 10.4.11. The interesting bit of historical trivia here is that IE5 works exactly opposite to the way IE8 works: the event-driven submit always supersedes the form.submit() method -- even when the click event has been inhibited from propagating by a return false; at the end of the onclick handler! (I haven't delved into whether this is a bug or a feature, though. I haven't yet -- and may never! -- run a test to determine whether it's botching the event inhibition, or trying to do something "smart".)

Still, regardless of the inconsistencies, both of the IEs only do a single submission.

My tentative (well, by now, actually pretty firm) conclusion is that the precise relationship between a "submit"-typed control and the DOM form.submit() method isn't well-defined, and that browser implementers, in the absence of any explicit guidance, generally do what they think best (see @Boris Zbarsky's answer, for example).

At least in the cases of Firefox, Safari and IE, their implementers foresaw the possibility that both an event and a method call might pete to submit the same form, and took steps (albeit different ones -- pretty much running the gamut) to ensure that only one of them would succeed.

(I'd still wele additional answers from folks who know different browser internals well enough to ment, or who've loaded my simple PHP script using browsers other than those I've tested.)

EDIT: Please read carefully all the way through the question before you consider answering it. I am not asking about the advisability of using an inline event handler in production code, nor am I asking about the best way to achieve the result promised by the article I reference. This is a question about Javascript semantics and browser implementation details, not about best coding practices.

Sounds like a nightmare, right?

Yet I found some online advice that advocates doing just such a thing to prevent double-submission of a form:

<input type="submit" 
       onclick="this.disabled=true;
                this.value='Sending, please wait...';
                this.form.submit();" />

Leaving aside any discussion of the evils of inline event handlers, the problems I see here are:

  1. The type of the tag is "submit", so submitting its containing form is its default behavior;
  2. The onclick handler explicitly submits the containing form;
  3. The onclick handler doesn't return false to prevent the default behavior (see 1).

Intuitively, I would think that a click on this item would do exactly the opposite of what the article claims -- i.e., submit the form twice, once as a result of the explicit submit() call, and then once more as the unsuppressed default behavior of the "submit"-typed control.

On the other hand, I wrote a tiny PHP script (below) and tried it out with both Firefox and Safari (at the moment my only conveniently available browsers), and it only writes a single log entry per click on the button:

<html>
<head></head>
<body>
<?php
  if (isset($_GET['action']) && $_GET['action'] == 'submit') {
    $s = 'Got form submission at ' . time();
    error_log($s);
    echo $s;
  }
  else {
?>
  <form action="http://localhost/~hephaestus/phptests/submittest.php?action=submit" 
        method="post">
    <input type="submit" 
           onclick="this.disabled=true;
                    this.value='Sending, please wait...';
                    this.form.submit();" />
  </form>
<?php
  }
?>
</body>
</html>

So are these two browsers actually doing the "right" thing (where "right" is defined in some document that I either haven't seen or haven't read closely enough) -- meaning that my analysis of the problems is inplete or wrong?

Or, is my analysis correct -- meaning that the observed single submissions are the result of the browser implementers putting in special-case logic, to save naive coders from themselves?

UPDATE:

In an effort to empirically test out the claim by @sourcecode that the form.submit() method is some sort of "second submit button" on a form, and is thus subject to the rule stated in section 17.13.2 of the HTML4 spec that there can only be one "successful" submit button, I made a few additions to my PHP test script:

<?php
  if (isset($_GET['action']) && $_GET['action'] == 'submit') {
    $s = 'Got form submission at ' . time() . ', tellme = ' . $_POST['tellme'];
    error_log($s);
    echo $s;
  }
  else {
?>
  <form action="http://localhost/~hephaestus/phptests/submittest.php?action=submit" 
        method="post">
    <input type="hidden" id="tellme" name="tellme" value="0" />
    <input type="submit" 
           onclick="this.disabled=true;
                    this.value='Sending, please wait...';
                    this.form.submit();
                    document.getElementById('tellme')=1;" />
  </form>
<?php
  }
?>

In Firefox, this code produces the single error-log entry:

Got form submission at timestamp, tellme = 1

which does suggest that the method-invocation is somehow being superseded by the intrinsic event-driven behavior of the control.

Furthermore, if I include an additional return false; after setting the value of tellme to 1 (thereby preventing the click event from propagating, and thus preventing the intrinsic behavior of the control), the single error-log entry is:

Got form submission at timestamp, tellme = 0

meaning that in this case, the submission was the result of the invocation of this.form.submit().

On the other hand, when I try the same two variations in Safari, each of them gives me the same single error-log entry:

Got form submission at timestamp, tellme = 0

So in the case of Safari, the method invocation always takes precedence over the event-driven submission -- presumably because it happens earlier.

That's. Just. Awesome. :-/

Further update: I got a chance to test this on IE 8.0 on Windows NT 5.1.

IE 8 mirrors the behavior of Safari, i.e., the form.submit() method always takes precedence over the even-driven submit.

Although it's hardly relevant today, I also realized that I have an ancient IE 5.22 on an even more ancient PowerPC iMac running OS X 10.4.11. The interesting bit of historical trivia here is that IE5 works exactly opposite to the way IE8 works: the event-driven submit always supersedes the form.submit() method -- even when the click event has been inhibited from propagating by a return false; at the end of the onclick handler! (I haven't delved into whether this is a bug or a feature, though. I haven't yet -- and may never! -- run a test to determine whether it's botching the event inhibition, or trying to do something "smart".)

Still, regardless of the inconsistencies, both of the IEs only do a single submission.

My tentative (well, by now, actually pretty firm) conclusion is that the precise relationship between a "submit"-typed control and the DOM form.submit() method isn't well-defined, and that browser implementers, in the absence of any explicit guidance, generally do what they think best (see @Boris Zbarsky's answer, for example).

At least in the cases of Firefox, Safari and IE, their implementers foresaw the possibility that both an event and a method call might pete to submit the same form, and took steps (albeit different ones -- pretty much running the gamut) to ensure that only one of them would succeed.

(I'd still wele additional answers from folks who know different browser internals well enough to ment, or who've loaded my simple PHP script using browsers other than those I've tested.)

Share Improve this question edited Sep 22, 2019 at 16:58 Brian Tompsett - 汤莱恩 5,89372 gold badges61 silver badges133 bronze badges asked Jan 6, 2013 at 6:01 HephaestusHephaestus 2,0723 gold badges30 silver badges37 bronze badges 2
  • When inline JavaScript looks like that is time to think about separating logic and markup... – elclanrs Commented Jan 6, 2013 at 6:04
  • Right, but you'll notice that I said "Leaving aside any discussion of the evils of inline event handlers..." This question is about something else altogether, i.e., Javascript semantics and browser implementation. – Hephaestus Commented Jan 6, 2013 at 6:08
Add a ment  | 

4 Answers 4

Reset to default 3

Gecko (Firefox) certainly detects multiple submissions and cancels older ones when new ones happen. See the mPendingSubmisson member in http://hg.mozilla/mozilla-central/file/c4abfca219e5/content/html/content/src/nsHTMLFormElement.h and the handling of it in http://hg.mozilla/mozilla-central/file/c4abfca219e5/content/html/content/src/nsHTMLFormElement.cpp (e.g. in nsHTMLFormElement::Submit and nsHTMLFormElement::PostHandleEvent (the latter being what gets called from the default action stuff for submit controls).

In terms of what the spec says, it's not clear to me that the spec is necessarily sane, but it lives at http://www.whatwg/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#concept-form-submit and suggests that both submissions would happen, but the later might effectively cancel the earlier because of internal details of the "navigate" algorithm. I filed https://www.w3/Bugs/Public/show_bug.cgi?id=20580 to sort the spec out.

This is w3 org remendation that:

  • If a form contains more than one submit button, only the activated submit button is successful.

    Same is there with Submit Click and local JS form.Submit function , only the "submit" is activated not form.submit function. Because submit is primary and JS function is secondary..
    you can learn more here link

I would imagine you would need to use the stopPropogation() method. Ideally You would call a function from your onclick handler instead of making it all inline.. see this other stackoverflow answer for a thorough explanation

NEVER execute script in onclick of a submit and for sure do NOT submit the form!!! Also if you disable the button the submit may be stopped!

If the code in the article works it is by sheer luck and I imagine many browsers entering into a racing condition of having a disabled submit button and a submit event in the click of this disabled button.

Here is an inline suggestion of something that aught to work in any browser

<form action="..." method="post" 
 onsubmit="document.getElementById('subbut').innerHTML='Sending, please wait...'">
  <span id="subbut"><input type="submit" /></span>
</form>

and the same unobtrusively:

window.addEventListener('load',function() {
  document.getElementById('form1').addEventListener('submit', function(e) {
    document.getElementById('subbut').innerHTML = 'Sending, please wait...';
  })
})
<form action="..." method="post" id="form1">
  <span id="subbut"><input type="submit" /></span>
</form>

本文标签: