如何避免在表单中重复点击按钮?

25

我的代码:

<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" oncomplete="Dlg.hide()" />
    </h:panelGrid>
</h:form>

保存操作涉及相当多的功能。如果我重复点击按钮,它可能会在数据库中保存几条记录。这不是我的意愿。我该如何防止多次点击并解决这个问题?


这个回答解决了你的问题吗?如何在JSF中实现双击预防 - Jasper de Vries
4个回答

41

<p:commandButton>的客户端API小部件:

  • PrimeFaces.widget.CommandButton

  • 方法 参数 返回类型 描述

  • disable() - void 禁用按钮

  • enable() - void 启用按钮

因此,您可以像这样使用:

<p:commandButton widgetVar="saveButton"
                 onclick="saveButton.disable()"
                 value="save"
                 action="#{treeTableController.saveNewNodes}" 
                 oncomplete="saveButton.enable();Dlg.hide()"
                 update="productDataForm"/>

是的,它真的有效!谢谢!在了解您的答案之前,我添加了以下内容**<p:ajaxStatus onstart="statusDialog.show();" onsuccess="statusDialog.hide();"/> <p:dialog modal="true" widgetVar="statusDialog" header="状态" draggable="false" closable="false"> <p:graphicImage value="/Resources/ajaxloadingbar.gif" /> </p:dialog> ** 我认为这些代码可以利用与 p:commandButton 相关的 ajax 功能。 - leo173
一点也不。是啊,你的猜测非常有说服力。呵呵。 - FishGel
12
对于较新版本的PrimeFaces(为此浪费了几分钟时间):<p:commandButton widgetVar="saveButton" onclick="PF('saveButton').disable()" oncomplete="PF('saveButton').enable()" value....意思是:创建一个带有widgetVar属性值为"saveButton"的命令按钮,当单击该按钮时,禁用它并在完成后启用它。 - esmin

11

对于更新版本的PrimeFaces,解决方案如下:

 <p:commandButton widgetVar="saveButton"
                 onclick="PF('saveButton').disable()"
                 value="save"
                 action="#{treeTableController.saveNewNodes}" 
                 oncomplete="PF('saveButton').enable();PF('Dlg').hide()"
                 update="productDataForm"/>

actionListener与action的区别 - romsky

3
使用JavaScript和计时器
<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>

谢谢您的回复!我认为@RichardDing的答案对我更好。 - leo173

3
作为一种通用的方法,您可以自定义按钮呈现器,以便自动应用修复程序到您应用中的所有(有资格的)按钮。
我使用此渲染器用于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>

这个渲染器是在PrimeFaces Extensions 8.0中添加的。如果您正在使用PFE,您可以将此渲染器简单地添加到您的faces-config.xml render-kit部分:

<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>

请查看https://www.primefaces.org/showcase-ext/sections/renderers/commandButtonSingleClick.jsf


我会将此作为PrimeFaces问题列表中的增强功能发布。非常好的方法!!! - Kukeltje
@Kukeltje - 我在 https://github.com/primefaces/primefaces/issues/2521 上发布了链接,该问题来自2017年。你创建了一个新的吗? - Ravi
@no... 我会意味着如果我是回答者,而不是我将要。 - Kukeltje

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接