Unable to handle onbeforeunload event using Angular Service

余生长醉 提交于 2019-12-22 10:07:44

问题


I have the following callback for my onbeforeUnload event in one of my service. In my app.run block I have:

window.onbeforeunload = Services.beforeWindowClose;

and this method is in a service:

this.beforeWindowClose = function (event) {
            var currentState = $state.current.name;
            if (currentState !== constant.LOGOUT) {
                $rootScope.$broadcast("close");
                if (Utilities.isSavePending)
                    event.returnValue = constant.MSG;
            }
        }

In my controllers I have :

$scope.$on("close", function () {
            Utilities.isSavePending = vm.save; //sets it to true
        })

Now given the events are synchronous in angular, this code should give me a popup on window close. However,this directly closes my window.

My intention is that whenever the user closes window, I raise an event and see if there is any unsaved data in my controller. If there is some unsaved data, the browser should not close and give a popup, while if there is no unsaved data, the browser should close.

Am I doing or understanding something wrong??


回答1:


In your module run function, you must declare beforeunload event this way :

.run(['$window', 'Utilities', function($window, Utilities) {  
  $window.addEventListener('beforeunload', function(e)         
     // Place code here
  };       
});

NOT this way :

.run(['$window', 'Utilities', function($window, Utilities) {  
    window.onbeforeunload = function() {         
     // Place code here
    };
}]);

Here is a snippet to use onbeforeunload event with Angular.

Note: depending on your browser, snippet won't work after you click Save item button and you try to close this window. You'll then need to paste the code in your own project.

Additional information

Recent HTML specifications now prevent customization of the popup message, a generic message is displayed instead.

It is therefore always possible to prevent navigation but it is no longer possible to specify a custom message

This always works on IE11 but it should not last long (until the next update).

HTML Specs about this : https://html.spec.whatwg.org/multipage/browsers.html#unloading-documents

Chrome/Safari docs about this : https://www.chromestatus.com/feature/5349061406228480

angular.module('app', []);

angular
  .module('app')
  .controller('ExampleController', ['$scope', 'Utilities', 'ItemService', function($scope, Utilities, ItemService) {
    // Expose Utilities to make pending state available in template
    $scope.Utilities = Utilities;
    // Use item service to save our item
    $scope.save = function() {
      ItemService.saveItem();
    }
    $scope.fireCloseEvent = function() {
      $scope.$emit('close');
    }
    $scope.$on('close', function(event) {
      Utilities.toggleSavePending();
    });
  }])
  .factory('ItemService', ['Utilities', function(Utilities) {
    return {
      saveItem: function() {
        // ...
        // Toggle global save pending state
        Utilities.toggleSavePending();
      }
    }
  }])
  .factory('Utilities', function() {
    var savePending = false;

    return {
      toggleSavePending: function() {
        savePending = !savePending;
      },
      isSavePending: function() {
        return savePending;
      }
    }
  })
  .run(['$window', 'Utilities', function($window, Utilities) {

    $window.addEventListener('beforeunload', function(e) {
      // If save pending state is truthy, prevent browser window from closing
      if (Utilities.isSavePending()) {
        var message = 'Warning! Save pending...';
        e = e || window.event;
        if (e) {
          e.returnValue = message;
        }
        return message;
      }
    });

  }]);
<!doctype html>
<html lang="en" ng-app="app">

<head>
  <meta charset="utf-8">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.min.js"></script>
  <script src="script.js"></script>
</head>

<body ng-controller="ExampleController">

  <button ng-click="save()" ng-disabled="Utilities.isSavePending()">Save item</button>
  <button ng-click="fireCloseEvent()">Fire Close Event</button>
  <div ng-if="Utilities.isSavePending()">A message should be displayed when you close the window</div>
</body>

</html>


来源:https://stackoverflow.com/questions/44132997/unable-to-handle-onbeforeunload-event-using-angular-service

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!