Evento de salida de página de interceptación

117

Al editar una página dentro de mi sistema, un usuario puede decidir navegar a otro sitio web y, al hacerlo, perder todas las ediciones que no ha guardado.

Me gustaría interceptar cualquier intento de ir a otra página y pedirle al usuario que se asegure de que quiere que esto suceda, ya que podría perder su trabajo actual.

Gmail hace esto de una manera muy similar. Por ejemplo, redacte un nuevo correo electrónico, comience a escribir en el cuerpo del mensaje e ingrese una nueva ubicación en la barra de direcciones (por ejemplo, twitter.com o algo). Le preguntará "¿Está seguro?"

Ideas de cómo replicar esto? Me dirijo a IE8, pero también me gustaría ser compatible con FF y Chrome.

Chris Ballance
fuente

Respuestas:

154

Similar a la respuesta de Ghommey, pero esto también es compatible con versiones antiguas de IE y Firefox.

window.onbeforeunload = function (e) {
  var message = "Your confirmation message goes here.",
  e = e || window.event;
  // For IE and Firefox
  if (e) {
    e.returnValue = message;
  }

  // For Safari
  return message;
};
Eli Grey
fuente
1
¿Podría explicar la primera línea (var message = ...)? No sé qué están haciendo esa coma y la segunda expresión.
mtmurdock
7
@mtmurdock Eso es solo sintaxis de Javascript para declarar múltiples variables. var foo, bar;es lo mismo quevar foo; var bar;
T Nguyen
4
@mtmurdock, La segunda declaración " var e = e || window.event;" significa establecer e igual al parámetro e (si es verdadero) o window.event si no es cierto. No será veraz si el parámetro e es nulo.
T Nguyen
3
@Blieque addEventListener no es compatible con IE8. No edite las respuestas de las personas sin siquiera leer la pregunta.
Eli Gray
2
Ya no funciona en Chrome (obsoleto): developers.google.com/web/updates/2016/04/…
Micha Schwab
25

Vea este artículo. La característica que está buscando es onbeforeunload

Código de muestra:

  <script language="JavaScript">
  window.onbeforeunload = confirmExit;
  function confirmExit()
  {
    return "You have attempted to leave this page.  If you have made any changes to the fields without clicking the Save button, your changes will be lost.  Are you sure you want to exit this page?";
  }
</script>
Jantimon
fuente
2
¿Hay alguna forma de identificar que el usuario ha optado por la opción "Salir de esta página" en lugar de "Permanecer en esta página"?
Shilpa Soni
@ShilpaSoni, en breve obtendría un evento de descarga posterior, developer.mozilla.org/en-US/docs/Web/API/Window/unload_event pero no creo que haya una forma sincrónica.
scipilot
6

En lugar de una ventana emergente de confirmación molesta, sería bueno retrasar el dejar solo un poco (cuestión de milisegundos) para administrar la publicación con éxito de los datos no guardados en el servidor, que administré para mi sitio escribiendo texto ficticio en la consola de esta manera:

window.onbeforeunload=function(e){
  // only take action (iterate) if my SCHEDULED_REQUEST object contains data        
  for (var key in SCHEDULED_REQUEST){   
    postRequest(SCHEDULED_REQUEST); // post and empty SCHEDULED_REQUEST object
    for (var i=0;i<1000;i++){
      // do something unnoticable but time consuming like writing a lot to console
      console.log('buying some time to finish saving data'); 
    };
    break;
  };
}; // no return string --> user will leave as normal but data is send to server

Editar: consulte también Synchronous_AJAX y cómo hacerlo con jquery

Remi
fuente
Me gusta esta alternativa a la ventana emergente. Gracias por la sugerencia, Remi.
Chris Ballance
2
eso no tiene absolutamente ningún sentido -1. javascript no está enhebrado, lo que está haciendo es hacer un postRequest y luego pausar el cálculo del sitio sin permitir que nadie haga nada (incluida su postRequest, que mientras tanto ya se envió antes de la pausa de cálculo).
fmsf
Y esa es exactamente la razón por la que funciona: de hecho, la solicitud posterior se envió antes de la pausa de cálculo, pero este pequeño bloqueo de la página antes de que se deje realmente asegura el tiempo suficiente para que el cliente del navegador (no javascript) realmente termine de enviar esta solicitud correctamente. . Noté que cuando solo envío la solicitud (sin bloquear) y salgo de la página inmediatamente después, la solicitud no siempre se envía.
Remi
6
No usaría eso en producción. console.log no es un navegador cruzado; cada postRequest sufre el retraso de las anteriores (lo que también significa que la página permanecerá allí mientras dure el bucle * solicitudes programadas); las solicitudes no se inician en paralelo; no está garantizado que realmente envíe sus solicitudes. Si me viera obligado a enfrentar este problema, optaría por una solicitud ajax sincrónica, si solo hay una solicitud. Con múltiples solicitudes, usaría solicitudes asíncronas ajax y un bucle que verifica los resultados (ya sea de éxito o de error) de las devoluciones de llamada de las solicitudes.
2012
No sabía que console.log no es entre navegadores y una solicitud Ajax sincrónica debería ser la solución preferida (para una sola solicitud). El mencionado SCHEDULED_REQUESTes un objeto que acumula cualquier información no urgente que deba enviarse al servidor, como un búfer de datos, uniendo efectivamente múltiples solicitudes a una (por supuesto que la url de estas solicitudes es la misma). El uso de una solicitud Ajax sincrónica antes de la descarga debería resolver el problema entre navegadores como dijiste. ¡Gracias por tu valioso comentario!
Remi
0

Tengo usuarios que no han completado todos los datos requeridos.

<cfset unloadCheck=0>//a ColdFusion precheck in my page generation to see if unload check is needed
var erMsg="";
$(document).ready(function(){
<cfif q.myData eq "">
    <cfset unloadCheck=1>
    $("#myInput").change(function(){
        verify(); //function elsewhere that checks all fields and populates erMsg with error messages for any fail(s)
        if(erMsg=="") window.onbeforeunload = null; //all OK so let them pass
        else window.onbeforeunload = confirmExit(); //borrowed from Jantimon above;
    });
});
<cfif unloadCheck><!--- if any are outstanding, set the error message and the unload alert --->
    verify();
    window.onbeforeunload = confirmExit;
    function confirmExit() {return "Data is incomplete for this Case:"+erMsg;}
</cfif>
Gordon
fuente