How to avoid repeatedly click a button in a form?
My code:
<h:form id="newBSTypePanel" >
<h:panelGrid columns="2" id="newRecod" >
<h:outputText value="Name"/><h:inputText value="#{treeTableController.newBStypeBean.currentObject.TYPENAME.value}" required="true" />
<p:commandButton value="save" action="#{treeTableController.saveNewNodes}" oncomplete="Dlg.hide()" update="productDataForm"/>
<p:commandButton value="close" oncompl开发者_如何学JAVAete="Dlg.hide()" />
</h:panelGrid>
</h:form>
There is quite a bit of functionality associated with the save action. If I click the button repeatedly, it may save a few records in the database. That's not my wish. How can I prevent multiple clicks and resolve this?
The <p:commandButton>
's Client Side API Widget:
PrimeFaces.widget.CommandButton
Method Params Return Type Description
disable()
- void Disables buttonenable()
- void Enables button
So you can just use like this:
<p:commandButton widgetVar="saveButton"
onclick="saveButton.disable()"
value="save"
action="#{treeTableController.saveNewNodes}"
oncomplete="saveButton.enable();Dlg.hide()"
update="productDataForm"/>
For the newer versions of PrimeFaces, the solution would be:
<p:commandButton widgetVar="saveButton"
onclick="PF('saveButton').disable()"
value="save"
action="#{treeTableController.saveNewNodes}"
oncomplete="PF('saveButton').enable();PF('Dlg').hide()"
update="productDataForm"/>
Use Javascript and Timer
<script>
function disableClick(){
document.getElementById('saveButton').disables = true;
setTimeout('document.getElementById(\'saveButton\').disables = false', 5000)"
}
</script>
<h:form id="newBSTypePanel" >
<h:panelGrid columns="2" id="newRecod" >
<h:outputText value="Name"/><h:inputText value="#{treeTableController.newBStypeBean.currentObject.TYPENAME.value}" required="true" />
<p:commandButton value="save" action="#{treeTableController.saveNewNodes}" oncomplete="Dlg.hide()" onclick="disableClick()" id="saveButton" update="productDataForm"/>
<p:commandButton value="close" oncomplete="Dlg.hide()" />
</h:panelGrid>
</h:form>
As a generic approach you could customize the button renderer, so you can automatically apply a fix to all (eligible) buttons in your application.
I use this renderer for a PrimeFaces p:commandButton
:
public class CommandButtonSingleClickRenderer extends CommandButtonRenderer {
@Override
protected void encodeMarkup(FacesContext context, CommandButton button) throws IOException {
if (isEligible(button)) {
final String widgetVar = button.resolveWidgetVar(context);
final String onClick = getAttributeValue(context, button, "onclick");
final String onComplete = getAttributeValue(context, button, "oncomplete");
button.setOnclick(prefix(onClick, getToggleJS(widgetVar, false)));
button.setOncomplete(prefix(onComplete, getToggleJS(widgetVar, true)));
}
super.encodeMarkup(context, button);
}
protected boolean isEligible(final CommandButton button) {
final ActionListener[] listeners = button.getActionListeners();
return button.isAjax()
&& button.isRendered()
&& (button.getActionExpression() != null || (listeners != null && listeners.length > 0))
&& !button.isDisabled()
&& !isConfirmation(button);
}
protected boolean isConfirmation(final CommandButton button) {
final String styleClass = button.getStyleClass();
return styleClass != null && styleClass.contains("ui-confirm");
}
protected String getToggleJS(final String widgetVar, final boolean enabled) {
return String.format("var w=PrimeFaces.widgets['%s'];if(w){w.%sable();};", widgetVar, enabled ? "en" : "dis");
}
protected String getAttributeValue(final FacesContext context, final CommandButton button, final String attribute) {
final ValueExpression ve = button.getValueExpression(attribute);
if (ve != null) {
return (String) ve.getValue(context.getELContext());
}
String key = attribute + "CommandButtonSingleClickRenderer";
String value = (String) button.getAttributes().get(key);
if (value == null) {
value = (String) button.getAttributes().get(attribute);
button.getAttributes().put(key, value == null ? Constants.EMPTY_STRING : value);
}
return value;
}
protected String prefix(final String base, final String prefix) {
return base == null ? prefix : prefix + base;
}
}
faces-config.xml:
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.CommandButtonRenderer</renderer-type>
<renderer-class>com.whatever.CommandButtonSingleClickRenderer</renderer-class>
</renderer>
</render-kit>
This renderer was added to PrimeFaces Extensions 8.0. If you are using PFE, you can simply add this renderer to your faces-config.xml render-kit
section:
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.CommandButtonRenderer</renderer-type>
<renderer-class>org.primefaces.extensions.renderer.CommandButtonSingleClickRenderer</renderer-class>
</renderer>
See https://www.primefaces.org/showcase-ext/sections/renderers/commandButtonSingleClick.jsf
精彩评论