AngularJS window.onbeforeunload在另一个控制器上被触发

AngularJS window.onbeforeunload in one controller is being triggered on another controller

这是我的问题,我有两个视图(View1和View2)以及每个视图的控制器(Ctrl1和Ctrl2)。在View1中,我试图在用户意外离开页面之前警告用户而不保存更改。

我正在使用window.onbeforeunload,效果很好,但是我的问题是,即使我仅在一个控制器上拥有onbeforeunload,该事件似乎也在第二个控制器中触发!但是我什至没有那个活动。当用户离开页面并且有未保存的更改时,如果用户关闭了警报并离开了页面,则他会被onbeforeunload警告,如果用户尝试现在离开另一个视图,则他将返回第二个视图,我们还会警告您未保存的更改!如果不是这样的话!为什么会这样呢?

我也使用$ locationChangeStart,它工作得很好,但是仅当用户更改路线时,而不是在刷新浏览器,点击"后退"或尝试关闭它时,这就是为什么我被迫使用onbeforeunload(如果您有更好的方法,请告诉我)。任何帮助或更好的方法将不胜感激!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//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()检查当前路径,以仅在用户在我希望触发onb??eforeunload的视图中时警告用户,但这似乎有点"棘手",解决方案是不对另一个执行onbeforeunload控制器。

我在第一个中添加了$ location.path()!='/ view1',但这似乎对我来说并不正确,除了我不仅有两个视图,我还有多个视图,这样可以棘手的涉及更多的控制器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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();
    }
  });
}

当定义它的控制器超出范围时,请注销onbeforeunload事件:

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


我只是尝试了上述解决方案,但对我来说却没有用。 即使在控制台中手动键入delete window.onbeforeunload也不会删除该功能。 我需要将属性设置为undefined。

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


对于使用angular-ui-router的用户,您可以使用$stateChangeStart而不是$locationChangeStart,例如

1
2
3
4
5
6
7
8
$scope.$on('$stateChangeStart', function (event){
  if (forbit){
    event.preventDefault()
  }
  else{  
    return
  }
})

作为对此的更新,对于任何使用angular-ui-router的人,我现在将$ transitions传递到您的控制器中并使用;

1
2
3
4
5
$transitions.onStart({}, function ($transition)
{
    $transition.abort();
    //return false;
});