views:

552

answers:

4

A poorly-written back-end system we interface with is having trouble with handling the load we're producing. While they fix their load problems, we're trying to reduce any additional load we're generating, one of which is that the back-end system continues to try and service a form submission even if another submission has come from the same user.

One thing we've noticed is users double-clicking the form submission button. I need to debounce these clicks, and prevent a second form submission. My approach (using Prototype) places an onSubmit on the form that calls the following function which hides the form submission button and displays a "loading..." div.

function disableSubmit(id1, id2) {
    $(id1).style.display = 'none';
    $(id2).style.display = 'inline';
}

The problem I've found with this approach is that if I use an animated gif in the "loading..." div, it loads fine but doesn't animate while the form is submitting.

Is there a better way to do this debouncing and continue to show animation on the page while waiting for the form result to (finally) load?

+1  A: 

You could try setting the "disabled" flag on the input (type=submit) element, rather than just changing the style. That should entirely shut down the from on the browser side.

See: http://www.prototypejs.org/api/form/element#method-disable

Jason Wadsworth
A: 

If you've got jQuery handy, attach a click() event that disables the button after the initial submission -

$('input[type="submit"]').click(function(e){
 event.preventDefault();
 this.click(null);
});

that sort of thing.

matt lohkamp
Even better I've discovered with jQuery is onesubmit()http://manalang.com/jquery/docs/index.html#onesubmit-fn
Shermozle
+2  A: 

Using Prototype, you can use this code to watch if any form has been submitted and disable all submit buttons when it does:

document.observe( 'dom:loaded', function() { // when document is loaded
    $$( 'form' ).each( function( form ) { // find all FORM elements in the document
        form.observe( 'submit', function() {  // when any form is submitted
            $$( 'input[type="submit"]' ).invoke( 'disable' );  // disable all submit buttons
        } );
    } );
} );

This should help with users that double-click on submit buttons. However, it will still be possible to submit the form any other way (e.g. pressing Enter on text field). To prevent this, you have to start watching for any form submission after the first one and stop it:

document.observe( 'dom:loaded', function() {
    $$( 'form' ).each( function( form ) {
        form.observe( 'submit', function() {
            $$( 'input[type="submit"]' ).invoke( 'disable' );
            $$( 'form' ).observe( 'submit', function( evt ) { // once any form is submitted
                evt.stop(); // prevent any other form submission
            } );
        } );
    } );
} );
Fczbkk
+1  A: 

All good suggestions above. If you really want to "debounce" as you say, then I've got a great function for that. More details at unscriptable.com

var debounce = function (func, threshold, execAsap) {

    var timeout;

    return function debounced () {
        var obj = this, args = arguments;
        function delayed () {
            if (!execAsap)
                func.apply(obj, args);
            timeout = null; 
        };

        if (timeout)
            clearTimeout(timeout);
        else if (execAsap)
            func.apply(obj, args);

        timeout = setTimeout(delayed, threshold || 100); 
    };

}
unscriptable