检测未保存的更改并使用angularjs提醒用户
以下是目前的代码
<!doctype html> <html ng-app> <head> <script src="1.1.2/angular.min.js"></script> <script type="text/javascript"> function Ctrl($scope) { var initial = {text: 'initial value'}; $scope.myModel = angular.copy(initial); $scope.revert = function() { $scope.myModel = angular.copy(initial); $scope.myForm.$setPristine(); } } </script> </head> <body> <form name="myForm" ng-controller="Ctrl"> myModel.text: <input name="input" ng-model="myModel.text"> <p>myModel.text = {{myModel.text}}</p> <p>$pristine = {{myForm.$pristine}}</p> <p>$dirty = {{myForm.$dirty}}</p> <button ng-click="revert()">Set pristine</button> </form> </body> </html>
如果有一些未保存的数据,如何提醒browser close
或url redirect
,以便用户可以决定是否继续?
像这样的东西应该这样做:
<!doctype html> <html ng-app="myApp"> <head> <script src="1.1.2/angular.min.js"></script> <script type="text/javascript"> function Ctrl($scope) { var initial = {text: 'initial value'}; $scope.myModel = angular.copy(initial); $scope.revert = function() { $scope.myModel = angular.copy(initial); $scope.myForm.$setPristine(); } } angular.module("myApp", []).directive('confirmOnExit', function() { return { link: function($scope, elem, attrs) { window.onbeforeunload = function(){ if ($scope.myForm.$dirty) { return "The form is dirty, do you want to stay on the page?"; } } $scope.$on('$locationChangeStart', function(event, next, current) { if ($scope.myForm.$dirty) { if(!confirm("The form is dirty, do you want to stay on the page?")) { event.preventDefault(); } } }); } }; }); </script> </head> <body> <form name="myForm" ng-controller="Ctrl" confirm-on-exit> myModel.text: <input name="input" ng-model="myModel.text"> <p>myModel.text = {{myModel.text}}</p> <p>$pristine = {{myForm.$pristine}}</p> <p>$dirty = {{myForm.$dirty}}</p> <button ng-click="revert()">Set pristine</button> </form> </body> </html>
请注意,$ locationChangeStart的侦听器在本例中没有触发,因为AngularJS在这个简单的例子中没有处理任何路由,但是它应该在实际的Angular应用中工作。
我已经扩展了@Anders的回答,在指令被销毁的时候(例如路由改变时)清理监听器(unbind listers),并添加一些语法糖来概括用法。
confirmOnExit指令 :
/** * @name confirmOnExit * * @description * Prompts user while he navigating away from the current route (or, as long as this directive * is not destroyed) if any unsaved form changes present. * * @element Attribute * @scope * @param confirmOnExit Scope function which will be called on window refresh/close or AngularS $route change to * decide whether to display the prompt or not. * @param confirmMessageWindow Custom message to display before browser refresh or closed. * @param confirmMessageRoute Custom message to display before navigating to other route. * @param confirmMessage Custom message to display when above specific message is not set. * * @example * Usage: * Example Controller: (using controllerAs syntax in this example) * * angular.module('AppModule', []).controller('pageCtrl', [function () { * this.isDirty = function () { * // do your logic and return 'true' to display the prompt, or 'false' otherwise. * return true; * }; * }]); * * Template: * * <div confirm-on-exit="pageCtrl.isDirty()" * confirm-message-window="All your changes will be lost." * confirm-message-route="All your changes will be lost. Are you sure you want to do this?"> * * @see * http://stackoverflow.com/a/28905954/340290 * * @author Manikanta G */ ngxDirectivesModule.directive('confirmOnExit', function() { return { scope: { confirmOnExit: '&', confirmMessageWindow: '@', confirmMessageRoute: '@', confirmMessage: '@' }, link: function($scope, elem, attrs) { window.onbeforeunload = function(){ if ($scope.confirmOnExit()) { return $scope.confirmMessageWindow || $scope.confirmMessage; } } var $locationChangeStartUnbind = $scope.$on('$locationChangeStart', function(event, next, current) { if ($scope.confirmOnExit()) { if(! confirm($scope.confirmMessageRoute || $scope.confirmMessage)) { event.preventDefault(); } } }); $scope.$on('$destroy', function() { window.onbeforeunload = null; $locationChangeStartUnbind(); }); } }; });
用法: 示例控制器 🙁 在此示例中使用controllerAs语法)
angular.module('AppModule', []).controller('pageCtrl', [function () { this.isDirty = function () { // do your logic and return 'true' to display the prompt, or 'false' otherwise. return true; }; }]);
模板 :
<div confirm-on-exit="pageCtrl.isDirty()" confirm-message-window="All your changes will be lost." confirm-message-route="All your changes will be lost. Are you sure you want to do this?">
Anders的答案工作正常,但是,对于使用Angular UI路由器的用户,您应该使用'$stateChangeStart'
而不是'$locationChangeStart'
。
我修改了@Anders答案,以便该指令不包含硬编码的表单名称:
app.directive('confirmOnExit', function() { return { link: function($scope, elem, attrs, ctrl) { window.onbeforeunload = function(){ if ($scope[attrs["name"]].$dirty) { return "Your edits will be lost."; } } } }; });
这是它的html代码:
<form name="myForm" confirm-on-exit>
也许这对别人有帮助 https://github.com/umbrella-web/Angular-unsavedChanges
使用这个服务,你可以监听范围内任何对象的未保存更改(不仅仅是表单)
要使用Anders Ekdahl对Angular 1.5组件的出色答案,请在组件的控制器中注入$scope
:
angular .module('myModule') .component('myComponent', { controller: ['$routeParams', '$scope', function MyController($routeParams, $scope) { var self = this; $scope.$on('$locationChangeStart', function (event, next, current) { if (self.productEdit.$dirty && !confirm('There are unsaved changes. Would you like to close the form?')) { event.preventDefault(); } }); } ] });