web-dev-qa-db-ja.com

あるコントローラーのAngularJS window.onbeforeunloadが別のコントローラーでトリガーされています

これが私の問題です。2つのビュー(View1とView2)と、各ビューのコントローラー(Ctrl1とCtrl2)があります。 View1では、ユーザーが誤って変更を保存せずにページを離れる前に、ユーザーに警告しようとしています。

私は問題なく動作するwindow.onbeforeunloadを使用していますが、私の問題は、1つのコントローラーでのみonbeforeunloadを持っているにもかかわらず、イベントが2番目のコントローラーでもトリガーされるように見えることです!しかし、私はそこにそのイベントさえ持っていません。ユーザーがページを離れて保存されていない変更がある場合、ユーザーがアラートを閉じてページを離れると、ユーザーは2番目のビューに戻りますか、ユーザーがこの別のビューを離れようとすると、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 ...
}

私はonlocationunloadをトリガーしたいビューにいるときにのみユーザーに警告するために$ location.path()で現在のパスをチェックしようとしましたが、これは他のonbeforeunloadを実行しないことですコントローラー。

私は$ location.path()を追加しました!= '/ view1'最初に動作しているようですが、私には正しくないようですが、2つのビューしか持っていないので、いくつかのビューがあり、これはより多くのコントローラーが関与することでトリッキーになります:

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

それを定義したコントローラーが範囲外になったら、onbeforeunloadイベントを登録解除します。

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

上記の解決策を試みたところ、それはうまくいきませんでした。手動で入力する場合でもdelete window.onbeforeunloadは、コンソールで関数を削除しません。代わりに、プロパティを未定義に設定する必要がありました。

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

angular-ui-router を使用している場合は、$stateChangeStart の代わりに $locationChangeStart、例:.

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

これの更新として、angular-ui-routerを使用する人のために、$ transitionsをコントローラーに渡して使用します。

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