Подтвердить что ты не робот

AngularJS window.onbeforeunload в одном контроллере запускается на другом контроллере

Вот моя проблема, у меня есть два представления (View1 и View2) и контроллер для каждого вида (Ctrl1 и Ctrl2). В View1 я пытаюсь предупредить пользователя, прежде чем он покинет страницу случайно, не сохраняя изменений.

Я использую window.onbeforeunload, который работает отлично, но моя проблема заключается в том, что даже если у меня есть onbeforeunload только на одном контроллере, событие, похоже, срабатывает и во втором контроллере! Но у меня даже нет такого события. Когда пользователь покидает страницу и появляются несохраненные изменения, он получает предупреждение от onbeforeunload, если пользователь упускает предупреждение и покидает страницу, возвращается ли он ко второму представлению, если пользователь пытается оставить это другое представление, мы также будем предупреждены о несохраненных изменениях! Когда это даже не случай! Почему это происходит?

Я также использую $locationChangeStart, который работает отлично, но только тогда, когда пользователь изменяет маршрут, а не когда он обновляет браузер, ударяет "назад" или пытается закрыть его, поэтому я вынужден используйте onbeforeunload (если вы лучше подходите, пожалуйста, дайте мне знать). Любая помощь или лучший подход были бы с благодарностью!

//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 ...
}

Я попытался проверить текущий путь с помощью $location.path(), чтобы только предупредить пользователя, когда он находится в представлении, я хочу, чтобы onbeforeunload запускался, но это кажется "хаки", решение должно состоять в том, чтобы не выполнять onbeforeunload на другом контроллере вообще.

Я добавил $location.path()!= '/view1' в первый, который, кажется, работает, но мне это кажется неправильным, кроме того, у меня есть не только два просмотров, у меня есть несколько просмотров, и это будет сложно с большим количеством задействованных контроллеров:

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

Ответ 1

Отмените регистрацию события onbeforeunload, когда контроллер, который его определил, выходит из области видимости:

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

Ответ 2

Я просто попытался решить вышеупомянутое решение, и это не работало для меня. Даже ручная настройка delete window.onbeforeunload в консоли не приведет к удалению функции. Мне нужно было установить свойство undefined.

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

Ответ 3

Для тех из вас, кто использует angular-ui-router, вы должны использовать $stateChangeStart вместо $locationChangeStart, например

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

Ответ 4

В качестве обновления к этому, для любого, кто использовал angular-ui-router, я бы сейчас передал $ переходы в ваш контроллер и использовал их;

$transitions.onStart({}, function ($transition)
{
    $transition.abort();
    //return false;
});