一个控制器中的AngularJS window.onbeforeunload正在另一个控制器上触发

Pon*_*cho 23 onbeforeunload angularjs

这是我的问题,我有两个视图(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 ...
}
Run Code Online (Sandbox Code Playgroud)

我尝试使用$ location.path()检查当前路径,仅在用户处于视图中时警告用户我希望触发onb​​eforeunload,但这似乎有点'hacky'解决方案是不在另一个上执行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();
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

小智 24

当定义它的控制器超出范围时,取消注册onbeforeunload事件:

$scope.$on('$destroy', function() {
    delete window.onbeforeunload;
});
Run Code Online (Sandbox Code Playgroud)


小智 20

我只是尝试了上面的解决方案,这对我不起作用.即使delete window.onbeforeunload在控制台中手动输入也不会删除该功能.我需要将属性设置为undefined.

$scope.$on('$destroy', function(e){
  $window.onbeforeunload = undefined;
});
Run Code Online (Sandbox Code Playgroud)

  • 可能是因为如果属性链存在于原型链中,则无法删除它们.设置`onbeforeunload = undefined`对我有用,而删除没有. (5认同)

小智 8

对于那些使用angular-ui-router的人,你会使用$stateChangeStart而不是$locationChangeStart,例如

$scope.$on('$stateChangeStart', function (event){
  if (forbit){
    event.preventDefault()
  }
  else{  
    return
  }
})
Run Code Online (Sandbox Code Playgroud)