Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

input type="submit", onclick handler calls this.form.submit(), and returns no value

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 incomplete 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 compete 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 welcome additional answers from folks who know different browser internals well enough to comment, or who've loaded my simple PHP script using browsers other than those I've tested.)

like image 905
Hephaestus Avatar asked Jan 06 '13 06:01

Hephaestus


People also ask

Can we use Onclick in submit button?

In javascript onclick event , you can use form. submit() method to submit form. You can perform submit action by, submit button, by clicking on hyperlink, button and image tag etc. You can also perform javascript form submission by form attributes like id, name, class, tag name as well.

What does JavaScript submit () do?

The method form. submit() allows to initiate form sending from JavaScript. We can use it to dynamically create and send our own forms to server.

Why submit button is not working in HTML?

Sometimes the problem is caused by old versions of the Javascript files, cached by your browser and can be fixed by clearing the browser cache. You can use the browser console of your browser for debugging. After the Javascript error is fixed, the submit button will automatically be enabled.

How do you make a form do nothing on submit?

To make HTML form submit do nothing with JavaScript, we return false in the submit handler. to set the onsubmit attribute to return false; to stop form submission when we click on the submit button.


1 Answers

Gecko (Firefox) certainly detects multiple submissions and cancels older ones when new ones happen. See the mPendingSubmisson member in http://hg.mozilla.org/mozilla-central/file/c4abfca219e5/content/html/content/src/nsHTMLFormElement.h and the handling of it in http://hg.mozilla.org/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.org/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.org/Bugs/Public/show_bug.cgi?id=20580 to sort the spec out.

like image 145
Boris Zbarsky Avatar answered Oct 16 '22 21:10

Boris Zbarsky