Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send an HTTP request onbeforeunload in AngularJS?

I have a simple angular app that has two views that are loaded using ngRoute. I need to do some clean up on the server when the user navigates between views and when the user leaves the page (refreshes window, closes tab, or closes browser).

My first stop was here: Showing alert in angularjs when user leaves a page. It solved the first case where the user navigates between views. I've handled the clean up like this:

$scope.$on('$locationChangeStart', function (event) {
    var answer = confirm("Are you sure you want to leave this page?")
    if (answer) {
        api.unlock($scope.id); //api is a service that I wrote. It uses angular $http service to handle communications and works in all other cases.
    } else {
        event.preventDefault();
    }
});

However, I haven't been able to handle the case where the user leaves the page. Following the above answer and this Google Groups post: https://groups.google.com/forum/#!topic/angular/-PfujIEdeCY I tried this:

window.onbeforeunload = function (event) {
    api.unlock($scope.id); //I don't necessarily need a confirmation dialogue, although that would be helpful. 
};

But it did not work. Then I've read here: How to execute ajax function onbeforeunload? that the request needs to be synchronous and here: How to $http Synchronous call with AngularJS that Angular does not support this (although this one might be outdated).

I've also tried calling $http directly (without the service) but that did not work either. At this point I'm stuck. Any suggestions / leads would be really appreciated.

Thanks in advance!

like image 734
Levon Tamrazov Avatar asked Feb 10 '14 22:02

Levon Tamrazov


People also ask

What is Onbeforeunload in JS?

The onbeforeunload event occurs when the document is about to be unloaded. This event allows you to display a message in a confirmation dialog box to inform the user whether he/she wants to stay or leave the current page.

What triggers Onbeforeunload?

The beforeunload event is fired when the window, the document and its resources are about to be unloaded. The document is still visible and the event is still cancelable at this point. This event enables a web page to trigger a confirmation dialog asking the user if they really want to leave the page.

What is the difference between unload and Beforeunload?

Purpose: The beforeunload event triggers right before unloading of the window has begun. unload would trigger while unloading of the window is taking place.


2 Answers

Solution is to call $rootScope.$digest(); after firing your $http calls in your onbeforeunload callback. The reason is that angular's $http methods wrap the config in an immediately resolved promise which means the ajax request doesn't actually get fired until the next tick. Other browsers appear to allow one more tick after the onbeforeunload tick, but not IE11 (the only version of IE in which I tested). Forcing the digest cycle avoids the need to wait until the next tick.

like image 155
Jason Rust Avatar answered Oct 18 '22 15:10

Jason Rust


The problem is that angular always make ASYNCHRONOUS calls with the $http service (and you can’t change that behavior). Since the page exits before the $http service have a chance to emit the requests you are not getting the desired result.

If you want a workarround without using any third party libraries try the following code:

var onBeforeUnload = function () {

    var data = angular.toJson($scope.id...);//make sure you $scope is legal here...
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open("POST", "apiURL/unlock", false);//the false is for making the call synchronous
    xmlhttp.setRequestHeader("Content-type", "application/json");
    xmlhttp.setRequestHeader("Authorization", token);
    xmlhttp.send(data);
}

It will block UI until the request is completed, so try to make the server fast or the user will notice.

like image 43
Jose Ch. Avatar answered Oct 18 '22 17:10

Jose Ch.