web-dev-qa-db-fra.com

Comment puis-je gérer l'événement de fermeture de l'onglet du navigateur dans Angular? Fermer seulement, pas rafraîchir

Mon objectif est de supprimer les cookies utilisateur lorsque l'onglet du navigateur est fermé.

C'est possible? Puis-je gérer l'événement de fermeture de l'onglet du navigateur sans actualiser le cas?

Si j'utilise des événements beforeunload ou unload, fonction déclenchée lors de l'actualisation de la page utilisateur, je ne veux pas cela, je veux simplement l'exécuter lorsque l'onglet est fermé.

Comment puis-je faire cela dans Angular?

26
Furkan Başaran

Ce n'est malheureusement pas un problème simple à résoudre. Mais cela peut être fait. La réponse ci-dessous est issue de nombreuses réponses différentes SO.

Partie simple: Sachant que la fenêtre est en train d'être détruite. Vous pouvez utiliser le descripteur d'événement onunload pour le détecter.

Partie délicate:

Détecter s'il s'agit d'une actualisation, d'un suivi de lien ou de l'événement de fermeture de fenêtre souhaité. La suppression du lien suit et la soumission des formulaires est assez simple:

var inFormOrLink;
$('a').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });

$(window).bind('beforeunload', function(eventObject) {
    var returnValue = undefined;
    if (! inFormOrLink) {
        returnValue = "Do you really want to close?";
    }
    eventObject.returnValue = returnValue;
    return returnValue;
}); 

Solution du pauvre

Vérification event.clientY ou event.clientX pour déterminer ce qui a été cliqué pour déclencher l'événement.

function doUnload(){
 if (window.event.clientX < 0 && window.event.clientY < 0){
   alert("Window closed");
 }
 else{
   alert("Window refreshed");
 }
}

L'axe des Y ne fonctionne pas car il est négatif pour les clics sur les boutons de rechargement ou de fermeture des onglets/fenêtres, et positif lorsque les raccourcis clavier sont utilisés pour recharger (par exemple F5, Ctrl-R, ...) et la fermeture de la fenêtre (par exemple Alt-F4 ). L'axe des X n'est pas utile car les différents navigateurs ont des emplacements de bouton différents. Cependant, si vous êtes limité, alors exécuter les coordonnées de l'événement à travers une série d'if-elses pourrait être votre meilleur pari. Attention, ce n'est certainement pas fiable.

Solution impliquée

(Tiré de Julien Kronegg ) Utilisation du stockage local HTML5 et du client/serveur AJAX. Avertissement: cette approche est limitée aux navigateurs qui prennent en charge le stockage local HTML5.

Sur votre page, ajoutez un onunload à la fenêtre du gestionnaire suivant

function myUnload(event) {
    if (window.localStorage) {
        // flag the page as being unloading
        window.localStorage['myUnloadEventFlag']=new Date().getTime();
    }

    // notify the server that we want to disconnect the user in a few seconds (I used 5 seconds)
    askServerToDisconnectUserInAFewSeconds(); // synchronous AJAX call
}

Ajoutez ensuite un onloadon le corps au gestionnaire suivant

function myLoad(event) {
    if (window.localStorage) {
        var t0 = Number(window.localStorage['myUnloadEventFlag']);
        if (isNaN(t0)) t0=0;
        var t1=new Date().getTime();
        var duration=t1-t0;
        if (duration<10*1000) {
            // less than 10 seconds since the previous Unload event => it's a browser reload (so cancel the disconnection request)
            askServerToCancelDisconnectionRequest(); // asynchronous AJAX call
        } else {
            // last unload event was for a tab/window close => do whatever
        }
    }
} 

Sur le serveur, collectez les demandes de déconnexion dans une liste et définissez un thread de minuterie qui inspecte la liste à intervalles réguliers (j'ai utilisé toutes les 20 secondes). Une fois le délai de demande de déconnexion écoulé (c'est-à-dire que les 5 secondes sont passées), déconnectez l'utilisateur du serveur. Si une annulation de demande de déconnexion est reçue entre-temps, la demande de déconnexion correspondante est supprimée de la liste, afin que l'utilisateur ne soit pas déconnecté.

Cette approche est également applicable si vous souhaitez faire la différence entre un événement de fermeture d'onglet/fenêtre et des liens suivis ou un formulaire soumis. Il vous suffit de mettre les deux gestionnaires d'événements sur chaque page qui contient des liens et des formulaires et sur chaque page de destination de lien/formulaire.

Commentaires de clôture (jeu de mots voulu):

Puisque vous souhaitez supprimer les cookies lorsque la fenêtre est fermée, je suppose que c'est pour les empêcher d'être utilisés lors d'une prochaine session. Si c'est une hypothèse correcte, l'approche décrite ci-dessus fonctionnera bien. Vous conservez le cookie invalidé sur le serveur (une fois le client déconnecté), lorsque le client crée une nouvelle session, le JS enverra le cookie par défaut, auquel cas vous savez qu'il provient d'une session plus ancienne, supprimez-le et fournissez éventuellement un nouveau à définir sur le client.

13
Varun Vohra
$window.addEventListener("beforeunload", function (e) {
  var confirmationMessage = "\o/";
  console.log("closing the tab so do your small interval actions here like cookie removal etc but you cannot stop customer from closing");
  (e || window.event).returnValue = confirmationMessage; //Gecko + IE
  return confirmationMessage;                            //Webkit, Safari, Chrome
});

Ceci est assez débattu pour savoir si nous pouvons le faire ou non d'une manière à toute épreuve. Mais techniquement, peu de choses peuvent être faites ici, car le temps dont vous disposez est bien moindre et si le client le ferme avant la fin de vos actions, vous avez des ennuis et vous êtes complètement à la merci du client. N'oubliez pas d'injecter $ window. Je conseille de ne pas en dépendre.

javascript détecte l'onglet de fermeture du navigateur/ferme le navigateur

Mise à jour: Je recherchais ce problème avec quelques recommandations. Et en dehors de cette option ci-dessus, la meilleure façon de gérer de tels cas est de créer des sessions sans délai d'activité de 25 à 30 minutes. Convertissez tous vos cookies qui doivent être détruits en sessions avec timeout. Alternativement, vous pouvez définir l'expiration du cookie, mais le cookie reste dans le navigateur jusqu'à la prochaine connexion. Moins de 25-30 minutes d'inactivité de session ne sont pas complètement fiables car vous pouvez vous déconnecter si le client n'utilise pas le navigateur pendant 10-15 minutes. J'ai même essayé de capturer des événements à partir d'événements liés (<a>) ou (<submit>) ou (keypress). Le problème est qu'il gère bien l'actualisation de la page. Mais cela ne supprime pas le problème de la fermeture du navigateur ou de l'onglet du navigateur par le client avant la suppression de vos cookies. C'est quelque chose que vous devez considérer dans votre cas d'utilisation et échanger avec force en raison de l'absence de contrôle sur celui-ci. Mieux vaut changer la conception en fonction de sa dépendance vers une meilleure architecture que de faire face aux problèmes mentionnés plus tard.

6
Gary
3
Adrian Stanescu

Je sais que cela fait un moment que cette question n'a pas été posée, mais j'ai pensé que j'apporterais également ma réponse. Le meilleur moyen que j'ai trouvé pour recharger la page sans perdre les cookies et supprimer les cookies à la fermeture de la fenêtre ou de l'onglet était d'utiliser ng-keydown pour regarder la touche F5 (KeyCode 116).

HTML

<body ng-controller="exitController" ng-keydown="isRefresh($event)">

CONTRÔLEUR

yourApp.controller('exitController', ['$rootScope', '$scope', '$window', '$cookies', function($rootScope, $scope, $window, $cookies) {
//set refresh to false to start out, it will become true only when we hit the refresh page
$scope.refresh = false;

//This is where we'll actually clear our cookies in the event of a window close
$scope.clearCookies = function() {
    $cookies.remove('sessionData');
    $cookies.remove('ss-id');
    $cookies.remove('ss-pid');
};

//When the user types any key, it will be assessed.
$scope.isRefresh = function(e) {
    var keyCode = e.keyCode; //find the key that was just pressed
    if(keyCode === 116) { //if the key that was pressed is F5, then we know it was a refresh
        $scope.refresh = true;
    }
}

//event that handles all refresh requests
window.onbeforeunload = function (e) {
    if (!$scope.refresh) { //as long as the trigger for the refresh wasnt initiated by F5, we remove the cookies
        $scope.clearCookies();
    }
};

}]);

1
GuyThreepwood64

Si votre objectif est de supprimer les cookies lorsque le navigateur est fermé, ne définissez pas d'expiration. Les cookies sans expiration sont supprimés à la fermeture du navigateur.

Vous ne devriez vraiment jamais avoir besoin de savoir si un utilisateur ferme son navigateur ou non. Je suis convaincu qu'il existe d'autres moyens d'accomplir tout ce que vous souhaitez faire.

Conclusion:

Si un visiteur n'est plus sur votre page, ce n'est vraiment pas à vous ce que l'utilisateur fait avec son navigateur ou son ordinateur. Ainsi, la détection de la fermeture du navigateur ne sera probablement jamais implémentée sans une sorte d'activation de l'utilisateur, par exemple, des extensions/plugins de navigateur.

0
flcoder