2014-08-27 17 views
21

Oto mój problem, mam dwa widoki (View1 i View2) i kontroler dla każdego widoku (Ctrl1 i Ctrl2). W widoku 1 próbuję ostrzec użytkownika przed przypadkowym opuszczeniem strony bez zapisywania zmian.AngularJS window.onbeforeunload w jednym kontrolerze jest wyzwalany na innym kontrolerze

Używam window.onbeforeunload, który działa dobrze, ale mój problem polega na tym, że mimo że mam onbeforeunload tylko na jednym kontrolerze, zdarzenie wydaje się być również wyzwalane w drugim kontrolerze! Ale nie mam tam nawet tego wydarzenia. Kiedy użytkownik opuszcza stronę i są niezapisane zmiany, zostaje ostrzeżony przez onbeforeunload, jeśli użytkownik odrzuci alert i opuści stronę, jest on przenoszony z powrotem do drugiego widoku, jeśli użytkownik próbuje opuścić ten inny widok, otrzymamy również ostrzeżenie o niezapisanych zmianach! Nawet jeśli tak nie jest! Dlaczego to się dzieje?

Używam również $ locationChangeStart, która działa dobrze, ale tylko wtedy, gdy użytkownik zmienia trasę, a nie kiedy odświeża przeglądarkę, uderza "wstecz" lub próbuje ją zamknąć, dlatego jestem zmuszony używać onbeforeunload (jeśli masz lepsze podejście, daj mi znać). Każda pomoc lub lepsze podejście będą bardzo mile widziane!

//In this controller I check for window.onbeforeunload 
app.controller("Ctrl1", function ($scope, ...)){ 
    window.onbeforeunload = function (event) {   

    //Check if there was any change, if no changes, then simply let the user leave 
    if(!$scope.form.$dirty){ 
     return; 
    } 

    var message = 'If you leave this page you are going to lose all unsaved changes, are you sure you want to leave?'; 
    if (typeof event == 'undefined') { 
     event = window.event; 
    } 
    if (event) { 
     event.returnValue = message; 
    } 
    return message; 
    } 

    //This works only when user changes routes, not when user refreshes the browsers, goes to previous page or try to close the browser 
    $scope.$on('$locationChangeStart', function(event) {  
    if (!$scope.form.$dirty) return; 
    var answer = confirm('If you leave this page you are going to lose all unsaved changes, are you sure you want to leave?') 
    if (!answer) { 
     event.preventDefault(); 
    } 
    }); 
} 

//This other controller has no window.onbeforeunload, yet the event is triggered here too! 
app.controller("Ctrl2", function ($scope, ...)){ 
    //Other cool stuff ... 
} 

Próbowałem sprawdzania aktualnego ścieżkę z $ location.path(), aby tylko ostrzega użytkownika, gdy jest on w widoku chcę onbeforeunload być wyzwalany, ale to wydaje się trochę „hacky” rozwiązaniem byłoby nie uruchamiać onbeforeunload na innym kontrolerze.

Dodałem $ location.path()! = '/ View1' w pierwszym, który wydaje się działać, ale nie wydaje mi się to właściwe, poza tym mam nie tylko dwa widoki, mam kilka widoków, a to się trudne z kilku kontrolerów zaangażowanych:

app.controller("Ctrl1", function ($scope, ...)){ 
    window.onbeforeunload = function (event) {   

    //Check if there was any change, if no changes, then simply let the user leave 
    if($location.path() != '/view1' || !$scope.form.$dirty){ 
     return; 
    } 

    var message = 'If you leave this page you are going to lose all unsaved changes, are you sure you want to leave?'; 
    if (typeof event == 'undefined') { 
     event = window.event; 
    } 
    if (event) { 
     event.returnValue = message; 
    } 
    return message; 
    } 

    //This works only when user changes routes, not when user refreshes the browsers, goes to previous page or try to close the browser 
    $scope.$on('$locationChangeStart', function(event) {  
    if (!$scope.form.$dirty) return; 
    var answer = confirm('If you leave this page you are going to lose all unsaved changes, are you sure you want to leave?') 
    if (!answer) { 
     event.preventDefault(); 
    } 
    }); 
} 

Odpowiedz

21

wyrejestrować zdarzenie onbeforeunload gdy kontroler, który ją zdefiniowano wychodzi z zakresu:

$scope.$on('$destroy', function() { 
    delete window.onbeforeunload; 
}); 
+0

Dokładnie to, czego potrzebowałem! Dziękuję Ci! – Poncho

18

właśnie próbował powyższy roztwór, i że nie działa dla mnie. Nawet ręczne wpisanie delete window.onbeforeunload w konsoli nie spowoduje usunięcia tej funkcji. Potrzebowałem zamiast tego ustawić właściwość na niezdefiniowaną.

$scope.$on('$destroy', function(e){ 
    $window.onbeforeunload = undefined; 
}); 
+3

Prawdopodobnie dlatego, że nie można usunąć właściwości, jeśli istnieją one w łańcuchu prototypów. Ustawienie 'onbeforeunload = undefined' działało dla mnie, podczas gdy delete nie. – spig

+0

Dokładny problem, z którym miałem do czynienia, Powyższa odpowiedź rozwiązała mój problem !! dzięki!! – OmPrakash

6

Dla tych używasz angular-ui-router użyłbyś jest $stateChangeStart zamiast $locationChangeStart, np

$scope.$on('$stateChangeStart', function (event){ 
    if (forbit){ 
    event.preventDefault() 
    } 
    else{ 
    return 
    { 
}) 
Powiązane problemy