32

我们有一些针对大量数据运行的搜索页面,需要一段时间才能完成。当用户点击搜索按钮时,我们不希望他们再次提交搜索结果。

是否有在 JSF 中进行“双击”检测/预防的最佳实践?

PrimeFaces 组件似乎可以做我们想做的事,因为它会在单击搜索按钮和搜索完成之间的一段时间内禁用 UI,但是我们可以使用更通用的策略(也许不是依赖于 PrimeFaces)?理想情况下,在搜索完成之前,对该按钮的任何点击都将被禁用或忽略。我们不一定需要禁用整个 UI(因为 blockUI 允许您这样做)。

4

8 回答 8

41

如果您仅使用 ajax 请求,则可以jsf.ajax.addOnEvent为此使用 JSF JavaScript API 的处理程序。下面的示例将适用于 的所有按钮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);

或者,如果您仅在特定按钮上需要此功能,请onevent使用<f:ajax>.

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

如果您还需要将此应用于同步请求,那么您需要考虑到,当您在 期间禁用按钮时onclick,按钮name=value对将不会作为请求参数发送,因此 JSF 将无法识别该操作并调用它。因此,您应该仅在浏览器发送 POST 请求禁用它。没有 DOM 事件处理程序,您需要使用setTimeout()在单击后禁用按钮约 50 毫秒的 hack。

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

这只是相当脆弱。对于慢速客户端,它可能太短了。您需要增加超时时间或转向其他解决方案。

也就是说,请记住,这只会在通过网页提交时防止重复提交。这不会阻止编程 HTTP 客户端(如URLConnectionApache HttpClient、Jsoup 等)的双重提交。如果您想在数据模型中强制执行唯一性,那么您不应该阻止双重提交,而是防止双重插入。UNIQUE这可以通过对感兴趣的列施加约束在 SQL 中轻松实现。

也可以看看:

于 2012-05-25T14:56:18.760 回答
2

我遇到了这个问题,遇到了同样的问题。该解决方案对我不起作用 - 在简要查看primefaces.js之后,我猜他们不再使用 jsf.ajax 了。

所以我必须自己解决一些问题,这是我的解决方案,对于那些也不能使用BalusC 答案中的人:

// we override the default send function of
// primeFaces here, so we can disable a button after a click
// and enable it again after     
var primeFacesOriginalSendFunction = PrimeFaces.ajax.AjaxUtils.send;

PrimeFaces.ajax.AjaxUtils.send = function(cfg){    
  var callSource = '';

  // if not string, the caller is a process - in this case we do not interfere
  if(typeof(cfg.source) == 'string') {
    callSource = jQuery('#' + cfg.source);
    callSource.attr('disabled', 'disabled');
  }

  // in each case call original send
  primeFacesOriginalSendFunction(cfg);

  // if we disabled the button - enable it again
  if(callSource != '') {
    callSource.attr('disabled', 'enabled');
  }
};
于 2013-10-09T12:17:03.940 回答
2

您可以使用“onclick”和“oncomplete”侦听器。当用户单击按钮时 - 禁用它。操作完成时 - 启用。

<p:commandButton id="saveBtn"
                 onclick="$('#saveBtn').attr('disabled',true);"
                 oncomplete="$('#saveBtn').attr('disabled',false);"
                 actionListener="#{myBean.save}" />
于 2013-10-30T17:29:54.830 回答
2

对我来说是这样工作的:

<h:commandLink ... onclick="jQuery(this).addClass('ui-state-disabled')">
于 2019-03-21T15:18:52.617 回答
1

上述替代方案都没有为我工作(我真的尝试过每一个)。当用户双击登录按钮时,我的表单总是发送两次。我在 Glassfish 3.1.2 上使用 JSF (Mojarra 2.1.6)。

考虑它是一个非 AJAX 登录页面。

所以这是我解决它的方法:

  1. 定义一个全局 JavaScript 变量来控制页眉或表单外任何地方的提交:
var submitting = false;
  1. 将其设置为触发true提交h:formonsubmit 事件时:
<h:form onsubmit="submitting = true">
  1. 在 h:commandLink 的点击事件中检查 var 的值:
<h:commandLink ... onclick="if(submitting){return false}">

这只是另一个简单的替代方案,它已在 Chrome [版本 47.0.2526.106(64 位)]、Mozilla Firefox (37.0.2) 和 Internet Explorer 11 中进行了测试。我希望它对某人有所帮助。

于 2016-05-13T23:36:43.277 回答
0

非常有用的解决方案 jsf-primefaces,与 facelets 模板一起使用传播到其他页面消费者

<f:view>
    <Script language="javascript">
        function checkKeyCode(evt)
        {
            var evt = (evt) ? evt : ((event) ? event : null);
            var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
            if(event.keyCode==116)
            {
                evt.keyCode=0;
                return false
            }
        }
        document.onkeydown=checkKeyCode;

        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);
    </Script>

</f:view>

<h:head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <link href="./resources/css/default.css" rel="stylesheet" type="text/css" />
    <link href="./resources/css/cssLayout.css" rel="stylesheet" type="text/css" />
    <title>infoColegios - Bienvenido al Sistema de Administracion</title>
</h:head>

<h:body onload="#{login.validaDatos(e)}">
    <p:layout fullPage="true">

        <p:layoutUnit position="north" size="120" resizable="false" closable="false" collapsible="false">                   
            <p:graphicImage value="./resources/images/descarga.jpg" title="imagen"/> 
            <h:outputText value="InfoColegios - Bienvenido al Sistema de Administracion" style="font-size: large; color: #045491; font-weight: bold"></h:outputText>                    
        </p:layoutUnit>

        <p:layoutUnit position="west" size="175" header="Nuestra Institución" collapsible="true" effect="drop" effectSpeed="">
            <p:menu> 
                <p:submenu>
                    <p:menuitem value="Quienes Somos" url="http://www.primefaces.org/showcase-labs/ui/home.jsf" />

                </p:submenu>
            </p:menu>
        </p:layoutUnit>

        <p:layoutUnit position="center">
            <ui:insert name="content">Content</ui:insert>
        </p:layoutUnit>

    </p:layout>
</h:body>

于 2013-01-04T00:25:56.397 回答
0

做了一个简单的隐藏和显示工作,适用于输入类型提交 Jquery 的元素

$(":submit").click(function (event) {
    // add exception to class skipDisable 
    if (!$(this).hasClass("skipDisable")) {
        $(this).hide();
        $(this).after("<input type='submit' value='"+$(this).val()+"' disabled='disabled'/>");
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<form>
    <input type="submit" value="hello">
</form>
于 2016-07-21T05:39:20.660 回答
0

BalusC的方法很棒,但是如果您使用 PrimeFaces,您会遇到样式问题。因为有些类没有被切换,所以按钮看起来不会被禁用。

如果您正在寻找一种同时处理样式的解决方案,您可以CommandButtonRenderer使用按钮的小部件将其替换为禁用单击按钮的解决方案以禁用和启用它。

PrimeFaces Extensions 8 或更高版本包含这样的渲染器。您可以将其添加到您的 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>
</render-kit>

您可以在展示中看到它的实际效果

如果您不能或不想使用 PFE,您可以通过以下方式将渲染类添加到您的项目中:

https://github.com/primefaces-extensions/primefaces-extensions/blob/master/core/src/main/java/org/primefaces/extensions/renderer/CommandButtonSingleClickRenderer.java

注意:这仍然需要您将渲染器添加到 faces-config.xml。

也可以看看

于 2020-02-24T08:44:26.883 回答