javascript - ventana - Avisar al usuario antes de abandonar la página web con cambios no guardados
title of page html (13)
Respuesta corta, incorrecta:
Puede hacer esto manejando el evento beforeunload
y devolviendo una cadena no nula :
window.addEventListener("beforeunload", function (e) {
var confirmationMessage = ''It looks like you have been editing something. ''
+ ''If you leave before saving, your changes will be lost.'';
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
});
El problema con este enfoque es que enviar un formulario también está activando el evento de descarga . Esto se soluciona fácilmente agregando la marca que está enviando un formulario:
var formSubmitting = false;
var setFormSubmitting = function() { formSubmitting = true; };
window.onload = function() {
window.addEventListener("beforeunload", function (e) {
if (formSubmitting) {
return undefined;
}
var confirmationMessage = ''It looks like you have been editing something. ''
+ ''If you leave before saving, your changes will be lost.'';
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
});
};
Luego llamando al setter al enviar:
<form method="post" onsubmit="setFormSubmitting()">
<input type="submit" />
</form>
Pero sigue leyendo ...
Respuesta larga y correcta:
Tampoco desea mostrar este mensaje cuando el usuario no ha cambiado nada en sus formularios . Una solución es usar el evento beforeunload
en combinación con un indicador "sucio", que solo activa el aviso si es realmente relevante.
var isDirty = function() { return false; }
window.onload = function() {
window.addEventListener("beforeunload", function (e) {
if (formSubmitting || !isDirty()) {
return undefined;
}
var confirmationMessage = ''It looks like you have been editing something. ''
+ ''If you leave before saving, your changes will be lost.'';
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
});
};
Ahora para implementar el método isDirty
, hay varios enfoques.
Puede usar jQuery y la serialización de formularios , pero este enfoque tiene algunas fallas. Primero, debe modificar el código para trabajar en cualquier formulario ( $("form").each()
lo hará), pero el mayor problema es que jQuery''s serialize()
solo funcionará en elementos con nombre, no deshabilitados, por lo que cambiará cualquier elemento deshabilitado o sin nombre no activará la bandera sucia. Hay soluciones para eso , como hacer controles de solo lectura en lugar de habilitar, serializar y luego deshabilitar los controles nuevamente.
Así que los eventos parecen ser el camino a seguir. Puedes intentar escuchar las pulsaciones de teclas . Este evento tiene algunos problemas:
- No se activará en las casillas de verificación, botones de radio u otros elementos que se modifiquen a través de la entrada del mouse.
- Se activará para pulsaciones de teclas irrelevantes como la tecla Ctrl .
- No activará los valores establecidos a través del código JavaScript.
- No se activará al cortar o pegar texto en los menús contextuales.
- No funcionará para entradas virtuales como selectores de fechas o embellecedores de casillas de verificación / botones de radio que guardan su valor en una entrada oculta a través de JavaScript.
El evento de change
tampoco se dispara en los valores establecidos desde el código JavaScript , por lo que tampoco funcionará para las entradas virtuales.
La vinculación del evento de input
a todas las input
s (y textarea
s y select
s) en su página no funcionará en los navegadores más antiguos y, como todas las soluciones de manejo de eventos mencionadas anteriormente, no admite el deshacer. Cuando un usuario cambia un cuadro de texto y luego lo deshace, o marca y desmarca una casilla de verificación, el formulario aún se considera sucio.
Y cuando quiera implementar más comportamiento, como ignorar ciertos elementos, tendrá aún más trabajo por hacer.
No reinventes la rueda:
Entonces, antes de pensar en implementar esas soluciones y todas las soluciones necesarias, comprenda que está reinventando la rueda y es propenso a tener problemas que otros ya han resuelto por usted.
Si su aplicación ya utiliza jQuery, también puede usar código mantenido y probado en lugar de rodar el suyo, y usar una biblioteca de terceros para todo esto. jQuery ¿Estás seguro? plugin funciona muy bien, ver su página de demostración . Es tan simple como esto:
<script src="jquery.are-you-sure.js"></script>
<script>
$(function() {
$(''#myForm'').areYouSure(
{
message: ''It looks like you have been editing something. ''
+ ''If you leave before saving, your changes will be lost.''
}
);
});
</script>
Mensajes personalizados no compatibles en todas partes
Tenga en cuenta que Firefox 4 no admite mensajes personalizados en este diálogo. A partir del mes pasado, Chrome 51 se está implementando en el que también se eliminan los mensajes personalizados .
Existen otras alternativas en este sitio, pero creo que un diálogo como este es lo suficientemente claro:
¿Quieres abandonar este sitio?
Es posible que los cambios realizados no se guarden.
Dejar quedarse
Tengo algunas páginas con formularios en mi solicitud.
¿Cómo puedo asegurar el formulario de tal manera que si alguien se aleja o cierra la pestaña del navegador, se le pida que confirme que realmente desea dejar el formulario con datos no guardados?
Agregando a la idea de @codecaster usted podría agregar esto a cada página con un formulario (en mi caso, lo uso de manera global, así que solo en los formularios tendría esta advertencia) cambiar su función para
if ( formSubmitting || document.getElementsByTagName(''form'').length == 0)
También incluya los formularios de envío, incluidos los enlaces de inicio de sesión y de cancelación, de modo que cuando una persona pulse Cancelar o envíe el formulario, no se activará la advertencia también en cada página de un formulario ...
<a class="btn btn-danger btn-md" href="back/url" onclick="setFormSubmitting()">Cancel</a>
Código siguiente funciona muy bien. Necesita llegar a los cambios de entrada de los elementos del formulario a través del atributo id:
var somethingChanged=false;
$(''#managerForm input'').change(function() {
somethingChanged = true;
});
$(window).bind(''beforeunload'', function(e){
if(somethingChanged)
return "You made some changes and it''s not saved?";
else
e=null; // i.e; if form state change show warning box, else don''t show it.
});
});
Construido sobre la excelente idea de Wasim A. de usar la serialización. El problema era que la advertencia también se mostraba cuando se enviaba el formulario. Esto se ha solucionado aquí.
var isSubmitting = false
$(document).ready(function () {
$(''form'').submit(function(){
isSubmitting = true
})
$(''form'').data(''initial-state'', $(''form'').serialize());
$(window).on(''beforeunload'', function() {
if (!isSubmitting && $(''form'').serialize() != $(''form'').data(''initial-state'')){
return ''You have unsaved changes which will not be saved.''
}
});
})
Ha sido probado en Chrome e IE 11.
Echa un vistazo a el JavaScript en el developer.mozilla.org/en/DOM/window.onbeforeunload Es un JavaScript no estándar introducido por Microsoft, sin embargo, funciona en la mayoría de los navegadores y su documentación antes de descargar tiene más información y ejemplos.
El siguiente one-liner me ha funcionado.
window.onbeforeunload = s => modified ? "" : null;
Solo modified
como verdadero o falso según el estado de su aplicación.
En base a las respuestas anteriores, y reunidas desde varios lugares en el desbordamiento de pila, esta es la solución que se me ocurrió para resolver el caso cuando realmente desea enviar sus cambios:
window.thisPage = window.thisPage || {};
window.thisPage.isDirty = false;
window.thisPage.closeEditorWarning = function (event) {
if (window.thisPage.isDirty)
return ''It looks like you have been editing something'' +
'' - if you leave before saving, then your changes will be lost.''
else
return undefined;
};
$("form").on(''keyup'', ''textarea'', // You can use input[type=text] here as well.
function () {
window.thisPage.isDirty = true;
});
$("form").submit(function () {
QC.thisPage.isDirty = false;
});
window.onbeforeunload = window.thisPage.closeEditorWarning;
Vale la pena señalar que IE11 parece requerir que la función closeEditorWarning
devuelva undefined
para que no muestre una alerta.
En primer lugar, la mayoría de los navegadores tienen esta función por defecto. ¿Y por qué necesitas esto en absoluto? ¿Por qué no mantener el formulario sincronizado? Quiero decir, guardarlo en cualquier cambio sin esperar ningún envío del usuario. Como lo hacen los contactos de Google. Por supuesto si solo todos los campos en forma son obligatorios. A los usuarios no les gusta cuando los obligan a llenar algo sin la oportunidad de irse a pensar si lo necesitan. :)
Puede consultar una explicación detallada aquí: http://techinvestigations.redexp.in/comparison-of-form-values-on-load-and-before-close/ compare-of-form-values-on-load-and -Antes de cerrar
El código principal:
function formCompare(defaultValues, valuesOnClose) {
// Create arrays of property names
var aPropsFormLoad = Object.keys(defaultValues);
var aPropsFormClose = Object.keys(valuesOnClose);
// If number of properties is different,
// objects are not equivalent
if (aPropsFormLoad.length != aPropsFormClose.length) {
return false;
}
for (var i = 0; i < aPropsFormLoad.length; i++) {
var propName = aPropsFormLoad[i];
// If values of same property are not equal,
// objects are not equivalent
if (defaultValues[aPropsFormLoad]+"" !== valuesOnClose[aPropsFormLoad]+"") {
return false;
}
}
// If we made it this far, objects
// are considered equivalent
return true;
}
//add polyfill for older browsers, as explained on the link above
//use the block below on load
for(i=0; i < document.forms[0].elements.length; i++){
console.log("The field name is: " + document.forms[0].elements[i].name +
" and it’s value is: " + document.forms[0].elements[i].value );
aPropsFormLoad[i] = document.forms[0].elements[i].value;
}
//create a similar array on window unload event.
//and call the utility function
if (!formCompare(aPropsOnLoad, aPropsOnClose))
{
//perform action:
//ask user for confirmation or
//display message about changes made
}
Respuesta corta:
let pageModified = true
window.addEventListener("beforeunload",
() => pageModified ? ''Close page without saving data?'' : null
)
Solución universal que no requiere una configuración que detecte automáticamente todas las modificaciones de entrada, incluidos los elementos editables de contenido
"use strict";
(() => {
const modified_inputs = new Set;
const defaultValue = "defaultValue";
// store default values
addEventListener("beforeinput", (evt) => {
const target = evt.target;
if (!(defaultValue in target || defaultValue in target.dataset)) {
target.dataset[defaultValue] = ("" + (target.value || target.textContent)).trim();
}
});
// detect input modifications
addEventListener("input", (evt) => {
const target = evt.target;
let original;
if (defaultValue in target) {
original = target[defaultValue];
} else {
original = target.dataset[defaultValue];
}
if (original !== ("" + (target.value || target.textContent)).trim()) {
if (!modified_inputs.has(target)) {
modified_inputs.add(target);
}
} else if (modified_inputs.has(target)) {
modified_inputs.delete(target);
}
});
addEventListener("beforeunload", (evt) => {
if (modified_inputs.size) {
const unsaved_changes_warning = "Changes you made may not be saved.";
evt.returnValue = unsaved_changes_warning;
return unsaved_changes_warning;
}
});
})();
a través de jQuery
$(''#form'').data(''serialize'',$(''#form'').serialize()); // On load save form current state
$(window).bind(''beforeunload'', function(e){
if($(''#form'').serialize()!=$(''#form'').data(''serialize''))return true;
else e=null; // i.e; if form state change show warning box, else don''t show it.
});
Puede la función de JQuery Form Serialize de Google, esto recopilará todas las entradas del formulario y las guardará en una matriz. Supongo que esta explicación es suficiente :)
var unsaved = false;
$(":input").change(function () {
unsaved = true;
});
function unloadPage() {
if (unsaved) {
alert("You have unsaved changes on this page. Do you want to leave this page and discard your changes or stay on this page?");
}
}
window.onbeforeunload = unloadPage;