2009-03-01 23 views
35

Tengo un formulario HTML con más de 20 campos. También tengo un par de enlaces en la página que alejarán al usuario del formulario ... potencialmente sin haber guardado ningún cambio.¿Cuál es la forma más fácil de detectar si se ha cambiado al menos un campo en un formulario HTML?

Quiero advertir (JS confirme) al usuario enHaga clic en estos enlaces si alguno de los campos del formulario ha cambiado, pero no quiero crear una gran declaración de cambio que deba mantener a medida que añada nuevos campos a la forma. Sé cómo crear una larga lista de declaraciones 'if' en Javascript, nombrando cada uno de los campos y comprobando cada valor, pero no quiero hacer eso si puedo salirse con la suya.

¿Cuál es la forma más fácil de comprobar si el usuario ha cambiado al menos uno de los valores de campo?

Respuesta

7

El uso de jQuery es muy fácil. Debería poder utilizar la misma premisa para lograr el mismo resultado en vainilla javascript también.

var $inps = $('#myForm').find('input,select,textarea') 
    , formAltered = false 
; 
$inps.change(function() { 
    formAltered = true; 
    $inps.unbind('change'); // saves this function running every time. 
}); 

El único problema con esto es que si se cambia un valor, y luego cambia de nuevo a la original, que todavía va a informar de forma que sean alteradas.

+0

+1, Puede elaborar este para eliminar el caso de datos no cambia realmente - puede guardar el estado inicial y comparar a ella (caso onfocus uso para eso) y sólo a continuación, establecer la forma de "sucio" – Dror

+0

Puede mejorar la primera línea: 'var $ inps = $ ('# myForm: input'), formAltered = false;' – ANeves

68

Enfoque

  1. serializar la forma (y todos sus valores) antes de mostrarlo (jQuery way, Prototype way)
  2. serializarlo de nuevo en un manejador "onbeforeunload" caso

Si los dos no coinciden, entonces deben haber cambiado el formulario, así que devuelva una cadena (por ejemplo, "Tiene datos no guardados") desde su controlador onbeforeunload.

Este método permite que los campos de formulario evolucionen mientras que la lógica "confirmar si cambió" sigue siendo la misma.

Ejemplo(mixta jquery javascript y)

var form_clean; 

// serialize clean form 
$(function() { 
    form_clean = $("form").serialize(); 
}); 

// compare clean and dirty form before leaving 
window.onbeforeunload = function (e) { 
    var form_dirty = $("form").serialize(); 
    if(form_clean != form_dirty) { 
     return 'There is unsaved form data.'; 
    } 
}; 
+0

Ooo, esa es una idea realmente agradable. Bonito. –

+10

En 2014, ¿sigue siendo esta la mejor práctica? –

+0

¿Existe alguna razón por la que la 1.ª línea no sea simplemente 'var form_clean = $ (" form "). Serialize();'? – Edd

5

Aquí es un un trazador de líneas que se pueden agregar a sus formas:

$(':input',document.myForm).bind("change", function() { 
    enablePrompt(true); }); // Prevent accidental navigation away 

Y a continuación, puede hacer que el enableUnloadPrompt () función para todo el sitio:

function enablePrompt(enabled) { 
    window.onbeforeunload = enabled ? "Your changes are not saved!" : null; 
} 

Y, por último, antes de enviar el formulario correctamente, asegúrese de que:

enablePrompt(false); 

Esto no va a comprobar para ver si la forma es diferente en los valores, sólo si la forma se ha cambiado alguna vez por el usuario. Pero, es simple y fácil de usar.

3

Esto podría manejarse con solo una variable booleana, lo llamamos manipulación de bits sucios. Si ha observado, generalmente en páginas web, una vez que el usuario realiza alguna acción de edición en cualquiera de los campos, el formulario se considera sucio (editado) (incluso si los datos permanecen sin cambios después de la edición). Cuando el usuario intenta navegar fuera de la página, se le solicita al usuario si desea guardar los cambios.

Según la práctica estándar, no hay verificación si después de editar algún campo si el valor realmente se cambió o no. Por ejemplo: si el usuario edita y agrega 'xyz' a un campo de texto y luego borra 'xyz' esencialmente los datos del formulario siguen siendo los mismos que antes, pero el formulario todavía se considera 'sucio' y el usuario recibe un mensaje de advertencia cuando intenta alejarse

Por lo tanto, si desea implementar esto, las cosas se vuelven bastante simples. Simplemente necesitaría agregar los manejadores de eventos change() a los controles y establecer la variable booleana global algo así como "dirty" en "true" dentro de esos eventhandlers.

Una vez que el usuario desea navegar, puede mostrar un mensaje "Es posible que haya cambios no guardados en la página actual. ¿Desea guardarlos?". El usuario no se decepcionará, incluso si nota que su edición no cambió los datos iniciales.

Las respuestas dadas anteriormente implementan este mismo comportamiento. Y escribí esto porque parecía tener una idea para verificar cada campo por su valor inicial para ver si realmente se modificó después de la edición. Solo quería decirte que revisar todos los campos no es necesario en absoluto.

11

Estoy bastante seguro de que esta es una mala idea, pero quería echarlo.

Los campos de formulario tienen una forma de obtener el "valor predeterminado" (es decir, el valor que tenía el campo cuando se cargó), y puede compararlo con el valor actual. Un bucle simple en todos los campos elimina la necesidad de mantenimiento si agrega campos al formulario.

Puede haber o no varios errores del navegador asociados con las propiedades del "valor predeterminado", por lo que no confiaría en este método sin realizar pruebas exhaustivas. El siguiente código es una prueba de concepto, y no lo utilizo (yo) en ninguna aplicación real.

function IsDirty(form) { 
    for (var i=0; i<form.elements.length; i++) { 
     var field = form.elements[i]; 
     switch (field.type) { 
      case "select-multiple": 
      case "select-one": 
       var options = field.options; 
       for (var j=0; j<options.length; j++) { 
        if(options[j].selected != options[j].defaultSelected) return true; 
       } 
       break; 
      case "text": 
      case "file": 
      case "password": 
       if (field.value != field.defaultValue) return true; 
       break; 
      case "checkbox": 
      case "radio": 
       if (field.checked != field.defaultChecked) return true; 
       break; 
     } 
    } 
    return false; 
} 
+0

Hasta donde yo sé, esta es la única forma de hacerlo. Previene la dificultad con, por ejemplo, Firefox, reteniendo los nuevos valores de formulario después de una actualización. –

Cuestiones relacionadas