We have a few search pages that run against a lot of data and take a while to complete. When a user clicks on the search button, we'd like to not allow them to submit the search result a second time.
Is there a best practice for doing "double-click" detection/prevention in JSF?
The PrimeFaces component seems like it can do what we want as it will disable the UI for a period of time between when the search button is clicked and when the search completes, but is there a more generic strategy we can use (perhaps something that isnt reliant on PrimeFaces)? Ideally, any click of the button will either be disabled or disregarded until the search completes. We dont necessarily need to disable the entire UI (as blockUI allows you to do).
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.