Как сделать предотвращение двойного щелчка в JSF 2

У нас есть несколько поисковых страниц, которые работают с большим количеством данных и требуют времени для завершения. Когда пользователь нажимает кнопку поиска, мы не хотим, чтобы он отправлял результаты поиска во второй раз.

Есть ли лучшая практика для выполнения "двойного щелчка"? обнаружение / профилактика в JSF?

Компонент PrimeFaces выглядит так, как будто он может делать то, что мы хотим, так как он будет отключать пользовательский интерфейс на период времени между нажатием кнопки поиска и завершением поиска, но есть ли более общая стратегия, которую мы можем использовать (возможно, это не зависит от PrimeFaces)? В идеале, любое нажатие кнопки будет либо отключено, либо проигнорировано до завершения поиска. Нам не обязательно отключать весь пользовательский интерфейс (как позволяет blockUI).

Ответы на вопрос(6)

ельно попробовал каждую из них). Моя форма всегда отправлялась дважды, когда пользователь дважды нажимал кнопку входа в систему. Я работаю с JSF (Mojarra 2.1.6) над Glassfish 3.1.2.

Учтите, что это была страница входа без AJAX.

Вот как я это решил:

define a global JavaScript var to control submition in the page header or anywhere outside your form:
var submitting = false;
set it to true when submit h:form onsubmit event is fired:
<h:form onsubmit="submitting = true">
Check the var's value on h:commandLink's click event:
<h:commandLink ... onclick="if(submitting){return false}">

Это просто еще одна простая альтернатива, и она была протестирована в Chrome [Версия 47.0.2526.106 (64-разрядная версия)], Mozilla Firefox (37.0.2) и Internet Explorer 11. Надеюсь, это кому-нибудь поможет.

 14 мая 2016 г., 05:11
Большое спасибо, @BestPractices, но я не понял твою точку зрения. Я перепробовал все другие альтернативы, и мое единственное, что работает в моем случае. Я не говорю, что они не правы, я просто разделяю мою точку зрения, пытаясь внести свой вклад в этот вопрос.
 BestPractices14 мая 2016 г., 02:40
Поверьте, у вас возникла проблема с кнопкой «Назад». Отправьте форму, а затем нажмите кнопку «Назад», чтобы вернуться на эту страницу. Значение отправляющей переменной, скорее всего, «истинно».

используемое с шаблонами 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>

хорошо работает с элементом, имеющим тип ввода submit 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>

имея ту же проблему. Решение не сработало для меня - после краткого взгляда на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');

  }

};
 21 июл. 2014 г., 14:05
Бит jquery должен быть callSource = $ (PrimeFaces .escapeClientId (cfg.source));
 21 июл. 2014 г., 14:17
Начиная с PrimeFaces 5, API изменился. PrimeFaces.ajax.AjaxUtils.send, вероятно, стал PrimeFaces.ajax.Request.send.
 21 июл. 2014 г., 14:08
Важно, чтобы код не запускался дважды (в противном случае вы быстро столкнетесь с проблемами производительности или даже сбоями).

слушатели. Когда пользователь нажимает на кнопку - отключить его. Когда действие выполнено - включите.

<p:commandButton id="saveBtn" onclick="$('#saveBtn').attr('disabled',true);" oncomplete="$('#saveBtn').attr('disabled',false);" actionListener="#{myBean.save}" />
 06 окт. 2014 г., 11:08
Это не сработало. Я все еще был в состоянии нажать кнопку несколько раз, пока действие обрабатывалось.
Решение Вопроса

вы можете использовать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 не сможет определить действие и вызвать его. Таким образом, вы должны только отключить егоafter запрос POST был отправлен браузером. Для этого нет обработчика событий DOM, вам нужно использоватьsetTimeout() Взлом, который отключает кнопку ~ 50 мс после нажатия.

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

Это только довольно хрупко. Это может быть слишком мало для медленных клиентов. Вам необходимо увеличить время ожидания или перейти к другому решению.

Тем не менее, имейте в виду, что это только предотвращает двойную передачу при отправке через веб-страницу. Это не предотвращает двойную передачу программными HTTP-клиентами, такими какURLConnection, Apache HttpClient, Jsoup и т. Д. Если вы хотите обеспечить уникальность в модели данных, то вам не следует предотвращать двойную передачу, а предотвращать двойную вставку. Это может быть легко достигнуто в SQL путемUNIQUE ограничение на столбец (ы) интереса.

See also: Pure Java/JSF implementation for double submit prevention How to handle multiple submits before response is rendered?

Ваш ответ на вопрос