Blog-Archiv

Donnerstag, 1. Dezember 2022

Prevent Double Submit on Chrome via JavaScript

Here is the continuation of my article about the browser-specific double submit problem.

Add following JavaScript to the bottom of the web page, right before the closing </body> tag:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
    <script>
    /**
     * Some browsers seem to launch two submit-requests on fast double click!
     * Calling this install-procedure will disable a clicked button after click,
     * this prevents any further click.
     * @param form optional, disable only submit-buttons of this form.
     *         When undefined or null, all submit-buttons of all forms in page will be disabled
     *         on submit of their form.
     * @param button optional, disable only this button. Requires a form.
     *         When undefined or null, all submit-buttons of all forms in page will be disabled
     *         on submit of their form.
     * @param installResetTimeout optional, when true,
     *         the button will be enabled again after 1 second.
     */
    function installDoubleSubmitPrevention(form, button, installResetTimeout) {
        function setButtonDisabled(btn) {
            btn.disabled = true;
            if (installResetTimeout) /* false for undefined and null */
                setTimeout(
                    () => btn.disabled = false,
                    1000
                );
        }
   
        function setFormButtonsDisabled(frm) {
            frm.querySelectorAll("input[type='submit']").forEach(
                (btn) => setButtonDisabled(btn)
            );
        }
   
        function installDoubleSubmitPreventionOnForm(frm) {
            frm.addEventListener("submit", () => setFormButtonsDisabled(frm));
        }
   
        if (form && button) {
            form.addEventListener("submit", () => setButtonDisabled(button));
        }
        else if (form) {
            installDoubleSubmitPreventionOnForm(form);
        }
        else {
            document.querySelectorAll("form").forEach(
                (frm) => installDoubleSubmitPreventionOnForm(frm)
            );
        }
    }
    
    installDoubleSubmitPrevention();
    
    </script>

On line 15, the definition of the install-function starts, which is then called on line 48. I call it without parameters, because that would manage all submit buttons in all forms by default. The documentation between line 2 and 14 tells you what you need to know about optional parameters.

Better would be to put the installDoubleSubmitPrevention function definition into a file js/preventDoubleSubmit.js and load it via a <script src="js/preventDoubleSubmit.js"></script> tag, so that you can reuse the function in many pages. In that case you would have to call installDoubleSubmitPrevention() explicitly in a second <script> tag. (For some reason you cannot put JS code into a tag that loads JS from a file!)

The install-function makes heavy use of the ES-6 lambda feature ("arrow-function"), to be seen on line 20, 27, 32, 36, 43, and thus may look short and simple, but is a little hard to read.

The setButtonDisabled function on line 16 sets the given button disabled, and optionally enables it after one second again, to be used in case the submit doesn't load a new page. (The timeout would be dismissed by the browser in case the submit loads a new page.)

The setFormButtonsDisabled function on line 25 calls the setButtonDisabled function for all submit-buttons of a given form.

The installDoubleSubmitPreventionOnForm function on line 31 installs the button-disabling on all submit-buttons of a given form.

All these nested functions exist to not duplicate code.

The install-logic starts on line 35, where the parameters are tested for existence, and according actions are taken. So you can call this function without arguments, or with a form, or with just a single button of a form. If you use the third parameter installResetTimeout and set it to true, a timeout that re-enables the button after 1 second would be installed. This can help when special treatments of the submit event were implemented on the page.
So, if you want to install the timeout on all buttons of all forms, call the function like this:

    installDoubleSubmitPrevention(undefined, undefined, true);



Keine Kommentare: