2014-02-10 2 views
8

Ich habe eine einfache eckige App, die zwei Ansichten hat, die mit ngRoute geladen werden. Ich muss etwas auf dem Server aufräumen, wenn der Benutzer zwischen Ansichten navigiert und wenn der Benutzer die Seite verlässt (Fenster wird aktualisiert, Tab geschlossen oder Browser geschlossen).Wie wird eine HTTP-Anfrage gesendet, bevor in AngularJS geladen wird?

Mein erster Halt war hier: Showing alert in angularjs when user leaves a page. Es löste den ersten Fall, in dem der Benutzer zwischen Ansichten navigiert. Ich habe die Reinigung wie folgt behandelt:

$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(); 
    } 
}); 

Allerdings war ich nicht in der Lage, den Fall zu behandeln, wo der Benutzer die Seite verlässt. Im Anschluss an die oben genannte Antwort und diesen Beitrag Google Groups: https://groups.google.com/forum/#!topic/angular/-PfujIEdeCY Ich versuchte dies:

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

Aber es hat nicht funktioniert. Dann habe ich hier gelesen: How to execute ajax function onbeforeunload?, dass die Anfrage synchron sein muss und hier: How to $http Synchronous call with AngularJS, dass Angular dies nicht unterstützt (obwohl diese möglicherweise veraltet ist).

Ich habe auch versucht, $ http direkt (ohne den Dienst) aufzurufen, aber das hat auch nicht funktioniert. An diesem Punkt stecke ich fest. Irgendwelche Vorschläge/Leads würden wirklich geschätzt werden.

Vielen Dank im Voraus!

+0

Sie könnten die Information anzeigen, dass Daten verloren gehen, wenn der Benutzer jetzt weg navigiert, geben Sie einfach eine Zeichenfolge innerhalb des onbeforeunload-Handlers zurück. – Sebastian

Antwort

13

Das Problem ist, dass eckige immer ASYNCHRONOUS-Aufrufe mit dem $ http-Dienst machen (und Sie können dieses Verhalten nicht ändern). Da die Seite beendet wird, bevor der $ http-Dienst eine Chance hat, die Anfragen zu senden, erhalten Sie nicht das gewünschte Ergebnis.

Wenn Sie ein workarround ohne irgendwelche Drittanbieter-Bibliotheken zu verwenden versuchen, den folgenden 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); 
} 

Es wird UI blockiert, bis die Anforderung abgeschlossen ist, so versucht der Server schnell zu machen oder der Benutzer bemerken.

+0

Dies hängt immer noch davon ab, welche Art von Serveranruf Sie machen. Ich versuche eine ähnliche Sache, wo ich den Server anrufe, um ein Sitzungsobjekt zu töten. Aber rannte zu dem Problem, wo der Benutzer nur die aktuelle Seite neu lädt :(also die Sitzung muss noch aktiv sein. –

7

Lösung ist $rootScope.$digest(); nach dem Brennen Ihrer $http Anrufe in Ihrem onbeforeunload Rückruf anrufen. Der Grund dafür ist, dass die Methoden $http von angular die config in eine sofort aufgelöste Zusage einschließen, was bedeutet, dass die Ajax-Anfrage erst beim nächsten Tick ausgelöst wird. Andere Browser scheinen einen weiteren Tick nach dem Tick onbeforeunload zu erlauben, aber nicht IE11 (die einzige Version von IE, in der ich getestet habe). Das Erzwingen des Digest-Zyklus vermeidet die Notwendigkeit, bis zum nächsten Tick zu warten.

+0

Das funktionierte für auf Chrome (Version 51.0.2704.103 (64-Bit)) –

+0

Vielen Dank! Dies funktionierte für IE11 für mich. – lwalden

Verwandte Themen