Comment puis-je remplacer la boîte de dialogue OnBeforeUnload et la remplacer par la mienne?

346

J'ai besoin d'avertir les utilisateurs des modifications non enregistrées avant de quitter une page (un problème assez courant).

window.onbeforeunload=handler

Cela fonctionne mais cela déclenche une boîte de dialogue par défaut avec un message standard irritant qui enveloppe mon propre texte. J'ai besoin de remplacer complètement le message standard, donc mon texte est clair, ou (encore mieux) de remplacer la boîte de dialogue entière par une boîte de dialogue modale utilisant jQuery.

Jusqu'à présent, j'ai échoué et je n'ai trouvé personne d'autre qui semble avoir une réponse. Est-ce même possible?

Javascript dans ma page:

<script type="text/javascript">   
   window.onbeforeunload=closeIt;
</script>

La fonction closeIt ():

function closeIt()
{
  if (changes == "true" || files == "true")
  {
      return "Here you can append a custom message to the default dialog.";
  }
}

En utilisant jQuery et jqModal, j'ai essayé ce genre de chose (en utilisant une boîte de dialogue de confirmation personnalisée):

$(window).beforeunload(function() {
        confirm('new message: ' + this.href + ' !', this.href);
        return false;
    });

qui ne fonctionne pas non plus - je n'arrive pas à me lier à l'événement beforeunload.

la chair
la source
1
pouvez-vous donner un exemple de votre code actuel et de ce qu'il produit?
Owen
Owen a raison. Et, la raison derrière cela est la sécurité. Empêcher le déchargement d'une page est utile dans les formulaires Web et autres, mais il peut facilement être exploité par un site malveillant pour tromper l'utilisateur pour qu'il reste sur une page. C'est pourquoi les navigateurs Web implémentent le message standard et disposent de ce mécanisme pour insérer du texte personnalisé.
pluckyglen
voir ici pour plus d'informations: stackoverflow.com/questions/140460
Ben McIntyre
1
impossible en chrome, référence: stackoverflow.com/questions/37782104/…
Abhijeet

Réponses:

300

Vous ne pouvez pas modifier la boîte de dialogue par défaut pour onbeforeunload, donc votre meilleur pari peut être de travailler avec elle.

window.onbeforeunload = function() {
    return 'You have unsaved changes!';
}

Voici une référence à cela de Microsoft:

Lorsqu'une chaîne est affectée à la propriété returnValue de window.event, une boîte de dialogue apparaît qui donne aux utilisateurs la possibilité de rester sur la page actuelle et de conserver la chaîne qui lui a été affectée. L'instruction par défaut qui apparaît dans la boîte de dialogue, "Êtes-vous sûr de vouloir quitter cette page? ... Appuyez sur OK pour continuer ou sur Annuler pour rester sur la page en cours.", Ne peut pas être supprimée ou modifiée.

Le problème semble être:

  1. Quand onbeforeunloadest appelé, il prendra la valeur de retour du gestionnaire comme window.event.returnValue.
  2. Il analysera ensuite la valeur de retour sous forme de chaîne (sauf si elle est nulle).
  3. Puisqu'il falseest analysé comme une chaîne, la boîte de dialogue se déclenchera, qui passera ensuite un true/ approprié false.

Le résultat est qu'il ne semble pas y avoir de moyen d'attribuer falseà onbeforeunloadpour l'empêcher de la boîte de dialogue par défaut.

Notes supplémentaires sur jQuery:

  • La définition de l'événement dans jQuery peut être problématique, car cela permet également à d'autres onbeforeunloadévénements de se produire. Si vous souhaitez uniquement que votre événement de déchargement se produise, je m'en tiendrai au simple JavaScript pour cela.
  • jQuery n'a pas de raccourci pour onbeforeunloadvous devez donc utiliser la bindsyntaxe générique .

    $(window).bind('beforeunload', function() {} );

Edit 09/04/2018 : les messages personnalisés dans les boîtes de dialogue onbeforeunload sont obsolètes depuis chrome-51 (cf: note de version )

Owen
la source
20
J'ai trouvé que l'exemple JQuery donné à la fin ne fonctionne pas dans Firefox. Restez plutôt simple: window.onbeforeunload = function () {...}
jb.
21
Juste une note que Firefox a été récemment modifié afin que le texte dans la boîte de dialogue ne puisse même pas être personnalisé: bugzilla.mozilla.org/show_bug.cgi?id=588292
David Hammond
15
Mais comment Facebook fournit-il alors une boîte de dialogue personnalisée? par exemple, accédez à la page des messages, répondez au message de votre ami, puis avant de cliquer sur envoyer, essayez de cliquer sur un autre lien. vous verrez une fenêtre de dialogue personnalisée
Varun
20
@Varun - vieilles nouvelles, mais Facebook met peut-être des gestionnaires sur l'événement click de toutes leurs ancres, mais si vous réécrivez l'URL dans le navigateur ou fermez la fenêtre, il revient à la méthode standard sur laquelle ils n'ont aucun contrôle.
Tabloo Quijico
1
@Varun Je suis également surpris que cette réponse qui rend cela impossible est marquée comme la réponse et que 150 votes positifs ... Je viens de réaliser que le message personnalisé de FB n'est disponible que via des liens à l'intérieur de leur site. Pas si vous vous éloignez simplement ...
Sébastien Richer
28

Ce qui a fonctionné pour moi, en utilisant jQuery et testé dans IE8, Chrome et Firefox, c'est:

$(window).bind("beforeunload",function(event) {
    if(hasChanged) return "You have unsaved changes";
});

Il est important de ne rien renvoyer si aucune invite n'est requise car il existe des différences entre IE et les autres comportements du navigateur ici.

grèbe
la source
Intéressant, event.returnValuec'est la seule méthode "approuvée" dans IE. IE poursuit en disant: «La valeur de cette propriété a priorité sur les valeurs renvoyées par la fonction, par exemple via une instruction de retour Microsoft JScript». .. ce serait bien de voir une corrélation garantie entre return(de l'événement) et event.returnValue..
21

Bien que vous ne puissiez rien faire à propos de la boîte dans certaines circonstances, vous pouvez intercepter quelqu'un en cliquant sur un lien. Pour moi, cela en valait la peine pour la plupart des scénarios et comme solution de repli, j'ai quitté l'événement de déchargement.

J'ai utilisé Boxy au lieu de la boîte de dialogue jQuery standard, elle est disponible ici: http://onehackoranother.com/projects/jquery/boxy/

$(':input').change(function() {
    if(!is_dirty){
        // When the user changes a field on this page, set our is_dirty flag.
        is_dirty = true;
    }
});

$('a').mousedown(function(e) {
    if(is_dirty) {
        // if the user navigates away from this page via an anchor link, 
        //    popup a new boxy confirmation.
        answer = Boxy.confirm("You have made some changes which you might want to save.");
    }
});

window.onbeforeunload = function() {
if((is_dirty)&&(!answer)){
            // call this if the box wasn't shown.
    return 'You have made some changes which you might want to save.';
    }
};

Vous pouvez vous attacher à un autre événement et filtrer davantage sur le type d'ancrage sur lequel vous avez cliqué, mais cela fonctionne pour moi et ce que je veux faire et sert d'exemple pour les autres à utiliser ou à améliorer. J'ai pensé que je partagerais cela pour ceux qui veulent cette solution.

J'ai coupé le code, donc cela peut ne pas fonctionner tel quel.

Dan Power
la source
return 'Vous avez apporté des modifications que vous souhaiterez peut-être enregistrer.' N'a pas travaillé pour moi. J'ai dû stocker le message dans une variable disant 'warning_message' et j'ai renvoyé warning_message. Alors seulement ça a marché pour moi !.
Suganya
avez-vous testé dans IE, Chrome, Firefox?
Kiquenet
9

1) Utilisez onbeforeunload, pas onunload.

2) L'important est d'éviter d'exécuter une déclaration de retour. Je ne veux pas, par cela, éviter de revenir de votre gestionnaire. Vous retournez bien, mais vous le faites en vous assurant que vous atteignez la fin de la fonction et n'exécutez PAS une instruction de retour. Dans ces conditions, la boîte de dialogue standard intégrée ne se produit pas.

3) Vous pouvez, si vous utilisez onbeforeunload, exécuter un appel ajax dans votre gestionnaire unbeforeunload pour ranger le serveur, mais il doit être synchrone, et vous devez attendre et gérer la réponse dans votre gestionnaire onbeforeunload (toujours en respectant condition (2) ci-dessus). Je fais ça et ça marche bien. Si vous effectuez un appel ajax synchrone, tout est suspendu jusqu'à ce que la réponse revienne. Si vous effectuez un appel asynchrone, pensant que vous ne vous souciez pas de la réponse du serveur, le déchargement de page continue et votre appel ajax est abandonné par ce processus - y compris un script distant s'il est en cours d'exécution.

user1164763
la source
Juste pour info toute personne lisant ceci ^ Chrome déprécie les appels AJAX synchrones dans unbeforeunload
morganwebdev
4

Essayez de placer un return;au lieu d'un message .. cela fonctionne pour la plupart des navigateurs. (Cela empêche seulement vraiment les cadeaux de dialogue)

window.onbeforeunload = function(evt) {            
        //Your Extra Code
        return;
}
Donald Powell
la source
3
return null empêchera l'ouverture de la boîte de dialogue
Brett Weber
1
return null n'empêchera PAS l'ouverture de la boîte de dialogue. Je l'ai essayé dans Chrome et ce n'est pas le cas.
Ray
2
Je peux également confirmer le commentaire de Ray dans IE. Le retour nullouvrira une boîte de dialogue avec le texte "null". Cependant, return void(0);n'ouvrira pas la boîte de dialogue.
MCattle
1
En ne mettant aucune instruction de retour dans la fonction beforeunload, la boîte de dialogue ne s'ouvrira pas.
OuuGiii
3

Vous pouvez détecter le bouton (ok ou annuler) appuyé par l'utilisateur, car la fonction onunload n'est appelée que lorsque l'utilisateur choisit de quitter la page. Bien que dans cette fonction, les possibilités soient limitées, car le DOM est en train de s'effondrer. Vous pouvez exécuter javascript, mais le POST ajax ne fait rien, vous ne pouvez donc pas utiliser cette méthode pour la déconnexion automatique. Mais il y a une solution à cela. Le window.open ('logout.php') exécuté dans la fonction onunload, donc l'utilisateur se déconnectera avec une nouvelle ouverture de fenêtre.

function onunload = (){
    window.open('logout.php');
}

Ce code est appelé lorsque l'utilisateur quitte la page ou ferme la fenêtre active et que l'utilisateur se déconnecte par 'logout.php'. La nouvelle fenêtre se ferme immédiatement lorsque la déconnexion php se compose de code:

window.close();
Tamas Cseh
la source
Vous pouvez utiliser un poste synchrone dans les fonctions beforeunload et unload. Surtout si vous avez besoin de données de retour du serveur. Tout code asynchrone dans ces blocs peut ne pas être terminé au moment du déchargement de la page.
jemiloii
3

J'ai rencontré le même problème, j'étais ok pour avoir sa propre boîte de dialogue avec mon message, mais le problème que j'ai rencontré était: 1) Il donnait un message sur toutes les navigations Je le veux uniquement pour un clic rapproché. 2) avec mon propre message de confirmation si l'utilisateur sélectionne annuler, il affiche toujours la boîte de dialogue par défaut du navigateur.

Voici le code des solutions que j'ai trouvé, que j'ai écrit sur ma page maître.

function closeMe(evt) {
    if (typeof evt == 'undefined') {
        evt = window.event; }
    if (evt && evt.clientX >= (window.event.screenX - 150) &&
        evt.clientY >= -150 && evt.clientY <= 0) {
        return "Do you want to log out of your current session?";
    }
}
window.onbeforeunload = closeMe;
Imran Rizvi
la source
1
 <script type="text/javascript">
        window.onbeforeunload = function(evt) {
            var message = 'Are you sure you want to leave?';
            if (typeof evt == 'undefined') {
                evt = window.event;
            }       
            if (evt) {
                evt.returnValue = message;
            }
            return message;
        } 
    </script>

référez-vous de http://www.codeprojectdownload.com

Krishna Patel
la source
1

Qu'en est-il de l'utilisation de la version spécialisée de la commande "bind" "one". Une fois que le gestionnaire d'événements s'exécute pour la première fois, il est automatiquement supprimé en tant que gestionnaire d'événements.

$(window).one("beforeunload", BeforeUnload);
Riga
la source
à peu près sûr que c'est .on ("beforeunload"
Sergiu Mindras
2
@SergiuMindras non, c'est .one()- qui attache un écouteur d'événements pour écouter l'événement ne se produire qu'une seule fois: "Attachez un gestionnaire à un événement pour les éléments. Le gestionnaire est exécuté au plus une fois par élément par type d'événement." api.jquery.com/one
Sean Kendle
0

Approche angulaire 9:

constructor() {
    window.addEventListener('beforeunload', (event: BeforeUnloadEvent) => {
     if (this.generatedBarcodeIndex) {
      event.preventDefault(); // for Firefox
      event.returnValue = ''; // for Chrome
      return '';
     }
     return false;
    });
   }

Prise en charge des navigateurs et suppression du message personnalisé:

  • Chrome a supprimé la prise en charge du message personnalisé dans la version 51 min
  • Opera a supprimé la prise en charge du message personnalisé dans la version 38 min
  • Firefox a supprimé la prise en charge du message personnalisé dans la version 44.0 min
  • Safari a supprimé la prise en charge du message personnalisé dans la version 9.1 min
Istvan Dembrovszky
la source