2008-09-26 13 views
18

Tenemos una aplicación web típica que es esencialmente una aplicación de entrada de datos con muchas pantallas, algunas de las cuales tienen cierto grado de complejidad. Necesitamos proporcionar esa capacidad estándar para asegurarnos de que si el usuario olvida hacer clic en el botón "Guardar" antes de navegar o cerrar su navegador recibe una advertencia y puede cancelar (pero solo cuando no hay datos sucios o no guardados).Cliente/JS Framework para la protección de "datos no guardados"?

Conozco los principios básicos de lo que tengo que hacer, de hecho, estoy seguro de que ya lo he hecho todo a través de los años (vinculado a antes de descargar, seguimiento del estado "sucio" de la página, etc ...) pero antes de embarcarme en codificar esto, ¿alguien tiene alguna sugerencia para las bibliotecas que ya existen (gratis o no) que ayudarán?

Respuesta

18

Una pieza del rompecabezas:

/** 
* Determines if a form is dirty by comparing the current value of each element 
* with its default value. 
* 
* @param {Form} form the form to be checked. 
* @return {Boolean} <code>true</code> if the form is dirty, <code>false</code> 
*     otherwise. 
*/ 
function formIsDirty(form) 
{ 
    for (var i = 0; i < form.elements.length; i++) 
    { 
     var element = form.elements[i]; 
     var type = element.type; 
     if (type == "checkbox" || type == "radio") 
     { 
      if (element.checked != element.defaultChecked) 
      { 
       return true; 
      } 
     } 
     else if (type == "hidden" || type == "password" || type == "text" || 
       type == "textarea") 
     { 
      if (element.value != element.defaultValue) 
      { 
       return true; 
      } 
     } 
     else if (type == "select-one" || type == "select-multiple") 
     { 
      for (var j = 0; j < element.options.length; j++) 
      { 
       if (element.options[j].selected != 
        element.options[j].defaultSelected) 
       { 
        return true; 
       } 
      } 
     } 
    } 
    return false; 
} 

And another:

window.onbeforeunload = function(e) 
{ 
    e = e || window.event; 
    if (formIsDirty(document.forms["someFormOfInterest"])) 
    { 
     // For IE and Firefox 
     if (e) 
     { 
      e.returnValue = "You have unsaved changes."; 
     } 
     // For Safari 
     return "You have unsaved changes."; 
    } 
}; 

envolverlo todo, y ¿qué se obtiene?

var confirmExitIfModified = (function() 
{ 
    function formIsDirty(form) 
    { 
     // ...as above 
    } 

    return function(form, message) 
    { 
     window.onbeforeunload = function(e) 
     { 
      e = e || window.event; 
      if (formIsDirty(document.forms[form])) 
      { 
       // For IE and Firefox 
       if (e) 
       { 
        e.returnValue = message; 
       } 
       // For Safari 
       return message; 
      } 
     }; 
    }; 
})(); 

confirmExitIfModified("someForm", "You have unsaved changes."); 

Es posible que también quieren cambiar el registro del manejador de beforeunload caso de utilizar el registro de eventos LIBRARY_OF_CHOICE 's.

+1

Gracias por todas las muestras ... sin duda hay suficiente aquí para trabajar con él, aunque todavía estoy luchando con la forma de manejar no atrapar las devoluciones de datos y lidiar con algunos paneles de Ajax. –

13

Si utiliza jQuery, aquí es un truco fácil:

$('input:text,input:checkbox,input:radio,textarea,select').one('change',function() { 
    $('BODY').attr('onbeforeunload',"return 'Leaving this page will cause any unsaved data to be lost.';"); 
}); 

Pero recuerda, si usted tiene una condición en la que se redirige desde esta página, o si desea permitir una forma exitosa posterior, es necesario hacer esto antes de que la redirección o presentados por el evento de este modo:

$('BODY').removeAttr('onbeforeunload'); 

... o te metes en un bucle donde se le mantiene pidiendo el símbolo.

En mi caso, tenía una gran aplicación y estaba haciendo redirecciones de location.href en Javascript, así como en la publicación de formularios, y luego algunos AJAX que luego vuelven con una respuesta exitosa en línea en la página. En cualquiera de esas condiciones, tuve que capturar ese evento y usar la llamada removeAttr().

+0

Por ahora, una mejor solución que encontré sobre este tema, en solo tres líneas. –

7

Quería ampliar ligeramente en Volomike el excelente código jQuery.

Así que con esto, tenemos un mecanismo muy, muy genial y elegante para lograr el objetivo de prevenir la pérdida de datos inadvertidos a través de navegar fuera de los datos actualizados antes de guardar, es decir. campo actualizado en una página, luego haga clic en un botón, enlace o incluso en el botón Atrás en el navegador antes de hacer clic en el botón Guardar.

Lo único que debe hacer es agregar una etiqueta de clase "no Warner" a todos los controles (especialmente a los botones Guardar) que devuelven una publicación al sitio web, que guarda o no elimina los datos actualizados.

Si el control hace que la página pierda datos, es decir. navega a la siguiente página o borra los datos; no es necesario que haga nada, ya que las secuencias de comandos mostrarán automáticamente el mensaje de advertencia.

¡Impresionante! ¡Bien hecho, Volomike!

simplemente tienen el código jQuery como sigue:

$(document).ready(function() { 

    //---------------------------------------------------------------------- 
    // Don't allow us to navigate away from a page on which we're changed 
    // values on any control without a warning message. Need to class our 
    // save buttons, links, etc so they can do a save without the message - 
    // ie. CssClass="noWarn" 
    //---------------------------------------------------------------------- 
    $('input:text,input:checkbox,input:radio,textarea,select').one('change', function() { 
     $('BODY').attr('onbeforeunload', 
     "return 'Leaving this page will cause any unsaved data to be lost.';"); 
    }); 

    $('.noWarn').click(function() { $('BODY').removeAttr('onbeforeunload'); }); 

}); 
7

adicional a la respuesta de Lance, yo pasamos una tarde tratando de obtener este fragmento en funcionamiento. En primer lugar, jquery 1.4 parece tener errores al vincular el evento de cambio (a partir de Feb '10). jQuery 1.3 está bien. En segundo lugar, no puedo obtener jquery para enlazar onbeforeunload/beforeunload (sospecho IE7, que estoy usando). He intentado diferentes selectores, ("cuerpo"), (ventana). He intentado '.bind', '.attr'. Volviendo a js puros trabajaron (también vi unos pocos puestos similares en lo que alrededor de este problema):

$(document).ready(function() { 
    $(":input").one("change", function() { 
     window.onbeforeunload = function() { return 'You will lose data changes.'; } 
    }); 
    $('.noWarn').click(function() { window.onbeforeunload = null; }); 
}); 

Nota También he utilizado el selector: en lugar de enumerar todos los tipos de entrada 'input'. Estrictamente exagerado, pero pensé que era genial :-)

+0

+1 por no funcionar en IE a menos que use vain js para el enlace. –

+0

+1 para "window.onbeforeunload = null;" –

1

Hice una pequeña mejora más a las implementaciones de jQuery enumeradas en esta página. Mi implementación se manejará si tiene validación de página ASP.NET en el lado cliente activada y en uso en una página.

Evita el "error" de borrar la función onBeforeLeave cuando la página no se publica al hacer clic debido a un error de validación. Simplemente use la clase no-warn-validate en botones/enlaces que causan validación. Todavía tiene la clase no-warn para usar en los controles que tienen CausesValidation=false (por ejemplo, un botón "Guardar como borrador"). Este patrón probablemente podría usarse para otros marcos de validación que no sean ASP.NET, así que publico aquí como referencia.

function removeCheck() { window.onbeforeunload = null; } 

$(document).ready(function() { 
    //----------------------------------------------------------------------------------------- 
    // Don't allow navigating away from page if changes to form are made. Save buttons, links, 
    // etc, can be given "no-warn" or "no-warn-validate" css class to prevent warning on submit. 
    // "no-warn-validate" inputs/links will only remove warning after successful validation 
    //----------------------------------------------------------------------------------------- 
    $(':input').one('change', function() { 
     window.onbeforeunload = function() { 
      return 'Leaving this page will cause edits to be lost.'; 
     } 
    }); 

    $('.no-warn-validate').click(function() { 
     if (Page_ClientValidate == null || Page_ClientValidate()) { removeCheck(); } 
    }); 

    $('.no-warn').click(function() { removeCheck() }); 
}); 
2

He creado un jQuery plug-in que se puede utilizar para implementar una advertirle-en-unsaved-cambios de funciones para aplicaciones web. Es compatible con las devoluciones de datos. También incluye un enlace a información sobre cómo normalizar el comportamiento del evento onbeforeunload de Internet Explorer.

Cuestiones relacionadas