2009-04-20 13 views
8

En una página con Ajax caso, quiero desactivar todas las acciones hasta que vuelva la llamada Ajax (para evitar problemas con doble presentar etc.)Javascript: ¿Cómo deshabilitar temporalmente todas las acciones en la página?

yo probamos este anteponiendo return false; a los eventos onclick actuales cuando "bloqueo" la página, y eliminar esto más adelante al "desbloquear" la página. Sin embargo, las acciones ya no están activas una vez que están "desbloqueadas"; simplemente no puedes dispararlas.

¿Por qué no funciona? Ver la página de ejemplo a continuación. ¿Alguna otra idea para lograr mi objetivo?

Ejemplo código:
tanto el enlace y el botón están mostrando una alerta de JS; al presionar Bloquear, desbloquear el controlador de eventos es el mismo que antes, pero no funciona ...?!?
El código está destinado a trabajar con Trinidad al final, pero debería funcionar también fuera.

<html><head><title>Test</title> 

<script type="text/javascript"> 
function lockPage() 
{ 
    document.body.style.cursor = 'wait'; 
    lockElements(document.getElementsByTagName("a")); 
    lockElements(document.getElementsByTagName("input")); 

    if (typeof TrPage != "undefined") 
    { 
    TrPage.getInstance().getRequestQueue().addStateChangeListener(unlockPage); 
    } 
} 

function lockElements(el) 
{ 
    for (var i=0; i<el.length; i++) 
    { 
    el[i].style.cursor = 'wait'; 
    if (el[i].onclick) 
    { 
     var newEvent = 'return false;' + el[i].onclick; 
     alert(el[i].onclick + "\n\nlock -->\n\n" + newEvent); 
     el[i].onclick = newEvent; 
    } 
    } 
} 

function unlockPage(state) 
{ 
    if (typeof TrRequestQueue == "undefined" || state == TrRequestQueue.STATE_READY) 
    { 
    //alert("unlocking for state: " + state); 
    document.body.style.cursor = 'auto'; 
    unlockElements(document.getElementsByTagName("a")); 
    unlockElements(document.getElementsByTagName("input")); 
    } 
} 

function unlockElements(el) 
{ 
    for (var i=0; i<el.length; i++) 
    { 
    el[i].style.cursor = 'auto'; 
    if (el[i].onclick && el[i].onclick.search(/^return false;/)==0) 
    { 
     var newEvent = el[i].onclick.substring(13); 
     alert(el[i].onclick + "\n\nunlock -->\n\n" + newEvent); 
     el[i].onclick = newEvent; 
    } 
    } 
} 
</script> 

<style type="text/css"> 
</style> 
</head> 

<body> 

<h1>Page lock/unlock test</h1> 

<p>Use these actions to lock or unlock active elements on the page: 
<a href="javascript:lockPage()">lock</a>, 
<a href="javascript:unlockPage()">unlock</a>.</p> 

<p>And now some elements:</p> 

<a onclick="alert('This is the action!');return false;" href="#">link action</a> &nbsp; 
<input type="button" value="button action" onclick="alert('This is another action!')"/> 
</body> 
</html> 

Gracias a todos por sus comentarios y respuestas.

Ahora veo que he mezclado Cuerdas y funciones, lo que obviamente no pueden trabajar; (

que debería haber dejado claro que usamos algunas FW y bibliotecas de etiquetas web (Trinidad) que crean el manejo de eventos (y Ajax) código, por lo tanto no puedo editar eso directamente o usar Ajax sincrónico, etc.

Además, Ajax es solo un escenario donde se debe ejecutar este código. Su propósito es evitar que el usuario doblemente envíe un página/acción, que también es relevante para páginas que no son de Ajax donde podría hacer clic en un botón. Sé que esto no es realmente seguro, y solo tiene que ser una cuestión de "conveniencia" para evitar la navegación página de error con demasiada frecuencia (tenemos protección del lado del servidor, por supuesto).

Por lo tanto, probaremos la superposición div, probablemente.

Gracias de nuevo,
Christoph.

Respuesta

9

¿Qué hay de la creación de una var mundial

actions_disabled = 0 

incremento cuando la llamada AJAX comienza entonces decremento cuando se termine. Todos los controladores de "acción" pueden comenzar con

if (actions_disabled) return false; 

¡Mucho más simple que la depuración del código de auto modificación!

Alternativamente, para bloquear los controles podría configurar:

control.disabled="disabled" 

que tendrá la ventaja de canas a cabo, por lo que es evidente para el usuario que no pueden someterse. Para desbloquear, basta con establecer:

control.disabled="" 

NUEVA IDEA Basándose en los comentarios (no se puede citar el código en los comentarios, parece ...):

Siempre se puede simplemente pasar el atributo extra en los objetos de Javascript:

Para bloquear, usted podría:

control.onclick_old = control.onclick 
control.onclick = "return false;" 

Para desbloquear, usted podría:

control.onclick = control.onclick_old 
+0

Gracias, pero desafortunadamente el código de acción es generado por el framework Trinidad y no puedo modificarlo directamente. Es por eso que tengo que usar JS para cambiar el código del controlador de eventos. – ami

+0

Puede "ajustar" las acciones: función thingo_wrap (e) { if (actions_disabled) return false; return original_thing (e) } Consulte también la sugerencia alternativa anterior. – NickZoic

+0

Buena idea ... No puedo hacer eso directamente, pero tal vez use algunos JS nuevamente para modificar la acción. La razón por la que mi solución original no funciona parece ser que estoy mezclando funciones y cadenas, ¿verdad? Lo intentaré. Alternativamente, probablemente podría usar un mapa para almacenar la acción original y restaurarla más tarde ... – ami

2

una vez logrado este objetivo mediante la creación de un DIV que cubría la zona que quería discapacitados, estableciendo su z-index más alto que cualquiera de los otros elementos de la página y, a continuación, establecer su opacity-0. De forma predeterminada, este DIV estaba oculto por display: none, por lo que no interferiría con nada. Sin embargo, cuando quería que el área fuera deshabilitada, simplemente configuré su display en block.

Steve

+0

Gracias por la respuesta, pero eso no es lo que el cliente quiere ... ;-( La página debe mostrarse sin cambios (con todos los botones, campos, etc. visibles) pero solo evitar que el usuario active otra acción o la misma acción por segunda vez. – ami

+0

Eso es lo que se sugiere. No habrá ningún cambio visible en la página. Ni siquiera necesita cambiar la opacidad, simplemente mantenga el div vacío y alternar el atributo de visualización entre 'ninguno' y 'bloquear' – ozan

+0

Oh, sí, ya veo. Debería haber leído esto con más detalle;) Probaremos ese enfoque ... – ami

1

AJAX. Asincrónico. Simplemente haga que la solicitud HTTP sea sincrónica. Problema resuelto.

+0

Bueno, tienes razón, pero ... Por un lado, esta parte del código es generada por nuestro Web FW y no tengo control directo sobre eso. Por otro lado, el propósito principal es evitar envíos dobles (como una capa adicional a la detección del lado del servidor existente), por lo que el mismo mecanismo debe usarse en todas las páginas, no solo para las llamadas Ajax. Acabo de mencionar a Ajax como ejemplo :( – ami

1

El problema con su código es el resultado de no entender los tipos en javascript.

Cuando dicen:

var newEvent = 'return false;' + el[i].onclick 

lo que esto hace es obligar el [i] .onclick (que es una función) a una cadena, entonces concatena a la cadena 'return false;'. Luego, cuando lo reasigne de la siguiente manera:

el[i].onclick = newEvent; 

onclick que anteriormente era una función ahora es una cadena.

Entonces intento de resucitar su antigua función de la cadena mediante la adopción de una subcadena:

var newEvent = el[i].onclick.substring(13); 

lo cual está bien, excepto newEvent sigue siendo una cadena! Entonces, cuando lo asigne de nuevo a OnClick, estará asignando la representación de cadena de la función original, no la función en sí.

Puede usar eval para evaluar la cadena y devolver la función, pero no haga eso. Hay varias formas mejores de hacerlo, como lo han sugerido otros comentaristas.

También me preguntaría por qué desea utilizar AJAX en absoluto si no desea permitir solicitudes asíncronas.

0

El uso de una superposición div no impide que un usuario ingrese en su página. Por lo general, eso está bien, ya que la mayoría de los usuarios no tabulan en ninguna página.

Si utiliza cualquier método abreviado de teclado en su página, seguirán estando disponibles, por lo que será necesario un manejo por separado.

Además, supongo que hacer clic en un elemento que puede tener el foco (por ejemplo, una etiqueta <a>), y luego presionar enter, todavía causaría una doble presentación.

Cuestiones relacionadas