Cómo hacer la prevención de doble clic en JSF 2


Tenemos algunas páginas de búsqueda que se ejecutan en contra de una gran cantidad de datos y tomar un tiempo para completar. Cuando un usuario hace clic en el botón de búsqueda, nos gustaría no permitirle enviar el resultado de la búsqueda por segunda vez.

¿Existe una mejor práctica para hacer detección/prevención de "doble clic" en JSF?

El componente PrimeFaces parece que puede hacer lo que queremos, ya que deshabilitará la interfaz de usuario durante un período de tiempo entre el momento en que se hace clic en el botón de búsqueda y cuando se completa la búsqueda, pero es ¿hay una estrategia más genérica que podamos usar (tal vez algo que no dependa de PrimeFaces)? Idealmente, cualquier clic en el botón será desactivado o no se tendrá en cuenta hasta que se complete la búsqueda. No necesariamente necesitamos deshabilitar toda la interfaz de usuario (como blockUI te permite hacer).

Author: BestPractices, 2012-05-25

6 answers

Si está utilizando únicamente solicitudes ajax, puede usar jsf.ajax.addOnEvent el controlador de la API JavaScript de JSF para esto. El siguiente ejemplo se aplicará a todos los botones de 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);

Alternativamente, si necesita esto solo en botones específicos, use el atributo onevent de <f:ajax>.

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

Si también necesita aplicar esto en solicitudes síncronas, debe tener en cuenta que cuando deshabilita un botón durante onclick, entonces el par name=value del botón no se enviará como parámetro de solicitud y por lo tanto JSF no será capaz de identificar la acción e invocarla. Por lo tanto, solo debe deshabilitarlo después de que el navegador haya enviado la solicitud POST. No hay controlador de eventos DOM para esto, usted tendría que utilizar el hack setTimeout() que desactiva el botón ~50ms después de hacer clic.

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

Esto es solo bastante frágil. Podría ser demasiado corto en clientes lentos. Tendría que aumentar el tiempo de espera o dirigirse a otra solución.

Dicho esto, tenga en cuenta que esto solo impide envíos dobles al enviar por una página web. Esto no impide el doble envío por parte de clientes HTTP programáticos como URLConnection, Apache HttpClient, Jsoup, etc. Si desea imponer la unicidad en el modelo de datos, no debe evitar los envíos dobles, sino evitar los insertos dobles. Esto se puede lograr fácilmente en SQL poniendo una restricción UNIQUE en la columna(s) de interés.

Véase también:

 32
Author: BalusC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:46:19

Me encontré con esta pregunta, teniendo el mismo problema. La solución no funcionó para mí - después de un breve vistazo a primefaces.js supongo que no usan jsf.ajax ya está ahí.

Así que tuve que resolver algo yo mismo y aquí está mi solución, para las personas que tampoco pueden usar la anterior:

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

  }

};
 1
Author: user2862701,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-09 12:17:03

Puede usar los oyentes 'onclick' y 'oncomplete'. Cuando el usuario haga clic en el botón - deshabilitarlo. Cuando se completa la acción-habilitar.

<p:commandButton id="saveBtn" onclick="$('#saveBtn').attr('disabled',true);" oncomplete="$('#saveBtn').attr('disabled',false);" actionListener="#{myBean.save}" />
 1
Author: Vladimir Tsukanov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-30 17:29:54

Solución muy útil jsf-primefaces, utilizado con la plantilla facelets se extiende a otras páginas consumidores

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

 0
Author: user1947165,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-04 00:25:56

Ninguna de las alternativas anteriores ha funcionado para mí (realmente he probado cada una de ellas). Mi formulario siempre fue enviado dos veces cuando el usuario hizo doble clic en el botón de inicio de sesión. Estoy trabajando con JSF (Mojarra 2.1.6) en Glassfish 3.1.2.

Considere que era una página de inicio de sesión no AJAX.

Así que esta es la forma en que lo resolví:

  1. defina una var global de JavaScript para controlar la sumisión en el encabezado de la página o en cualquier lugar fuera de su formulario:
var submitting = false;
  1. póngalo en true cuando enviar h:form se dispara el eventosububmit:
<h:form onsubmit="submitting = true">
  1. Compruebe el valor del var en el evento de clic de h: commandLink:
<h:commandLink ... onclick="if(submitting){return false}">

Esta es solo otra alternativa simple y se probó en Chrome [Versión 47.0.2526.106 (64-bit)], Mozilla Firefox (37.0.2) e Internet Explorer 11. Espero que ayude a alguien.

 0
Author: Jaumzera,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-13 23:36:43

Hizo un trabajo simple con ocultar y mostrar, funciona bien con el elemento que tiene el tipo de entrada enviar 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>
 0
Author: Anupam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-21 05:39:20