Événement de sortie de page d'interception

117

Lors de la modification d'une page dans mon système, un utilisateur peut décider de naviguer vers un autre site Web et, ce faisant, perdre toutes les modifications qu'il n'a pas enregistrées.

Je voudrais intercepter toute tentative d'aller sur une autre page et inviter l'utilisateur à être sûr qu'il souhaite que cela se produise, car il pourrait potentiellement perdre son travail actuel.

Gmail fait cela de manière très similaire. Par exemple, rédigez un nouvel e-mail, commencez à taper dans le corps du message et entrez un nouvel emplacement dans la barre d'adresse (par exemple, twitter.com ou quelque chose). Il vous demandera "Êtes-vous sûr?"

Des idées comment reproduire cela? Je cible IE8, mais j'aimerais également être compatible avec FF et Chrome.

Chris Ballance
la source

Réponses:

154

Similaire à la réponse de Ghommey, mais cela prend également en charge les anciennes versions d'IE et de 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 Gray
la source
1
Pouvez-vous expliquer la première ligne (var message = ...)? Je ne sais pas ce que font cette virgule et la deuxième expression.
mtmurdock
7
@mtmurdock C'est juste une syntaxe Javascript pour déclarer plusieurs variables. var foo, bar;est le même quevar foo; var bar;
T Nguyen
4
@mtmurdock, La deuxième instruction " var e = e || window.event;" signifie mettre e égal au paramètre e (si c'est vrai) ou window.event si ce n'est pas vrai. Ce ne sera pas vrai si le paramètre e est nul.
T Nguyen
3
@Blieque addEventListener n'est pas pris en charge dans IE8. Ne modifiez pas les réponses des gens sans même lire la question.
Eli Gray le
2
Ne fonctionne plus dans Chrome (obsolète): développeurs.google.com
web
25

Consultez cet article. La fonctionnalité que vous recherchez est la fonction onbeforeunload

exemple de code:

  <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
la source
2
Existe-t-il un moyen d'identifier que l'utilisateur a choisi l'option «Quitter cette page» plutôt que «Rester sur cette page»?
Shilpa Soni
@ShilpaSoni vous obtiendrez bientôt un événement de déchargement ultérieur, developer.mozilla.org/en-US/docs/Web/API/Window/unload_event mais je ne pense pas qu'il y ait un moyen synchrone.
scipilot
6

Au lieu d'une fenêtre contextuelle de confirmation ennuyeuse, il serait bien de retarder un peu de laisser un peu (question de millisecondes) pour gérer avec succès la publication des données non enregistrées sur le serveur, ce que j'ai géré pour mon site en écrivant un texte factice sur la console comme ceci:

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

Edit: Voir aussi Synchronous_AJAX et comment faire cela avec jquery

Remi
la source
J'aime cette alternative au popup. Merci pour la suggestion, Remi.
Chris Ballance
2
cela n'a absolument aucun sens -1. javascript n'est pas threadé ce que vous faites est de faire une postRequest puis de suspendre le calcul du site sans permettre à personne de ne rien faire (y compris votre postRequest, qui entre-temps a déjà été envoyée avant la pause de calcul).
fmsf
Et c'est exactement pourquoi cela fonctionne: en effet la post-requête a été envoyée avant la pause de calcul, mais ce petit blocage de la page avant qu'elle ne soit effectivement laissée assure suffisamment de temps au navigateur client (pas javascript) pour vraiment finir d'envoyer correctement cette requête . J'ai remarqué que lorsque j'envoie uniquement la demande (sans blocage) et que je quitte la page immédiatement après, la demande n'est pas toujours envoyée.
Remi du
6
Je n'utiliserais pas ça en production. console.log n'est pas crossbrowser; chaque postRequest souffre du retard des précédentes (ce qui signifie également que la page y restera pendant la durée de votre boucle * requêtes programmées); les demandes ne sont pas lancées en parallèle; vous n'êtes pas assuré d'envoyer vraiment vos demandes. Si j'étais obligé de faire face à ce problème, j'irais avec une requête ajax synchrone, s'il n'y a qu'une seule requête. Avec plusieurs demandes, j'utiliserais des demandes asynchrones ajax et une boucle qui vérifie les résultats (succès ou erreur) des rappels des demandes.
framp
Je ne savais pas que console.log n'est pas cross-browser et une requête Synchronous Ajax devrait en effet être la solution préférée (pour une seule requête). Le mentionné SCHEDULED_REQUESTest un objet qui accumule toutes les informations non urgentes qui devraient être envoyées au serveur, comme un tampon de données, joignant effectivement plusieurs requêtes à une seule (bien sûr, l'url de ces requêtes est la même). L'utilisation d'une requête Ajax synchrone avant le déchargement devrait résoudre le problème entre les navigateurs, comme vous l'avez dit. Merci pour votre précieux commentaire!
Remi
0

J'ai des utilisateurs qui n'ont pas rempli toutes les données requises.

<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
la source