How to do double-click prevention in JSF

Solution 1:

If you're using solely ajax requests, you could use jsf.ajax.addOnEvent handler of the JSF JavaScript API for this. The below example will apply on all buttons of type="submit".

function handleDisableButton(data) {
    if (data.source.type != "submit") {
        return;
    }

    switch (data.status) {
        case "begin":
            data.source.disabled = true;
            break;
        case "complete":
            data.source.disabled = false;
            break;
    }    
}

jsf.ajax.addOnEvent(handleDisableButton);

Alternatively, if you need this on specific buttons only, use the onevent attribute of <f:ajax>.

<h:commandButton ...>
    <f:ajax ... onevent="handleDisableButton" />
</h:commandButton>

If you also need to apply this on synchronous requests, then you need to take into account that when you disable a button during onclick, then the button's name=value pair won't be sent as request parameter and hence JSF won't be able to identify the action and invoke it. You should thus only disable it after the POST request has been sent by the browser. There is no DOM event handler for this, you'd need to use the setTimeout() hack which disables the button ~50ms after click.

<h:commandButton ... onclick="setTimeout('document.getElementById(\'' + this.id + '\').disabled=true;', 50);" />

This is only rather brittle. It might be too short on slow clients. You'd need to increase the timeout or head to another solution.

That said, keep in mind that this only prevents double submits when submitting by a web page. This does not prevent double submits by programmatic HTTP clients like URLConnection, Apache HttpClient, Jsoup, etc. If you want to enforce uniqueness in the data model, then you should not be preventing double submits, but preventing double inserts. This can in SQL easily be achieved by putting an UNIQUE constraint on the column(s) of interest.

See also:

  • Pure Java/JSF implementation for double submit prevention
  • How to handle multiple submits before response is rendered?

Solution 2:

For me works this way:

<h:commandLink ... onclick="jQuery(this).addClass('ui-state-disabled')">