如何在JSF 2中进行双击预防

时间:2012-05-25 14:41:21

标签: jsf-2 primefaces

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

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

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

7 个答案:

答案 0 :(得分:33)

如果您只使用ajax请求,则可以使用JSF JavaScript API的jsf.ajax.addOnEvent处理程序。以下示例将适用于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的{​​{1}}属性。

<f:ajax>

如果您还需要在同步请求中应用此功能,那么您需要考虑在<h:commandButton ...> <f:ajax ... onevent="handleDisableButton" /> </h:commandButton> 期间禁用按钮时,按钮的onclick对将不会作为请求发送参数,因此JSF将无法识别操作并调用它。因此,只有在浏览器发送了POST请求后才能将其禁用。没有DOM事件处理程序,你需要使用name=value hack,它会在点击后约50ms禁用按钮。

setTimeout()

这只是相当脆弱。慢客户端可能太短了。您需要增加超时或前往另一个解决方案。

这就是说,请记住,这只能防止在通过网页提交时提交双重提交。这不会阻止程序化HTTP客户端(如<h:commandButton ... onclick="setTimeout('document.getElementById(\'' + this.id + '\').disabled=true;', 50);" /> ,Apache HttpClient,Jsoup等)提交双重提交。如果要在数据模型中强制实施唯一性,则不应阻止双重提交,而是防止双重插入。通过在感兴趣的列上添加URLConnection约束,可以轻松地在SQL中实现这一点。

另见:

答案 1 :(得分:1)

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

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

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

  }

};

答案 2 :(得分:1)

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

<p:commandButton id="saveBtn" onclick="$('#saveBtn').attr('disabled',true);" oncomplete="$('#saveBtn').attr('disabled',false);" actionListener="#{myBean.save}" />

答案 3 :(得分: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>

答案 4 :(得分:0)

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

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

所以这就是我解决它的方式:

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

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

答案 5 :(得分:0)

使用hide和show进行简单的工作,对于具有输入类型的元素提交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>

答案 6 :(得分:0)

对我来说,是这样工作的:

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