Как сделать двойной клик в JSF 2
У нас есть несколько страниц поиска, которые работают против большого количества данных и требуют времени. Когда пользователь нажимает кнопку поиска, мы не хотим, чтобы они повторно отправляли результат поиска во второй раз.
Существует ли лучшая практика для "обнаружения/предотвращения двойного щелчка" в JSF?
Компонент PrimeFaces выглядит так, как будто он может делать то, что мы хотим, поскольку он будет отключать пользовательский интерфейс в течение периода времени между нажатием кнопки поиска и завершением поиска, но есть ли более общая стратегия, которую мы можем использовать (возможно, что-то, что не зависит от PrimeFaces)? В идеале, любой щелчок кнопки будет либо отключен, либо проигнорирован до тех пор, пока поиск не завершится. Нам не обязательно отключать весь пользовательский интерфейс (как позволяет blockUI).
Ответы
Ответ 1
Если вы используете исключительно запросы 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 мс после клика.
<h:commandButton ... onclick="setTimeout('document.getElementById(\'' + this.id + '\').disabled=true;', 50);" />
Это довольно хрупкое. Это может быть слишком мало для медленных клиентов. Вам нужно увеличить тайм-аут или перейти к другому решению.
Тем не менее, имейте в виду, что это предотвращает двойное подчинение при отправке с веб-страницы. Это не предотвращает двойные отправки программными HTTP-клиентами, такими как URLConnection
, Apache HttpClient, Jsoup и т.д. Если вы хотите обеспечить уникальность в модели данных, то вы не должны препятствовать двойным представлениям, а предотвращать двойные вставки. Это можно в SQL легко достичь, поставив ограничение UNIQUE
на интересующий столбец.
См. также:
Ответ 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');
}
};
Ответ 3
Вы можете использовать прослушиватели onclick и oncomplete. Когда пользователь нажимает кнопку - отключите его. Когда действие завершено - включите.
<p:commandButton id="saveBtn" onclick="$('#saveBtn').attr('disabled',true);" oncomplete="$('#saveBtn').attr('disabled',false);" actionListener="#{myBean.save}" />
Ответ 4
очень полезное решение 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>
Ответ 5
Никакие альтернативы выше не работали для меня (я действительно пробовал каждый из них). Моя форма всегда отправлялась дважды, когда пользователь дважды нажал кнопку входа в систему. Я работаю с JSF (Mojarra 2.1.6) на Glassfish 3.1.2.
Учтите, что это была страница входа в систему, отличную от AJAX.
Итак, вот как я его решил:
- определить глобальный JavaScript var для управления представлением в заголовке страницы или вне вашей формы:
var submitting = false;
- установите
true
при отправке h:form
onsubmit event:
<h:form onsubmit="submitting = true">
- Проверьте значение var в h: событие clickLink команды:
<h:commandLink ... onclick="if(submitting){return false}">
Это просто еще одна простая альтернатива, и она была протестирована в Chrome [версия 47.0.2526.106 (64-разрядная версия)], Mozilla Firefox (37.0.2) и Internet Explorer 11. Надеюсь, это поможет кому-то.
Ответ 6
Простая работа с hide и show, хорошо работает с элементом, имеющим тип ввода 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>
Ответ 7
У меня так работает:
<h:commandLink ... onclick="jQuery(this).addClass('ui-state-disabled')">