我在页面上有一个 ng 表单。在表单内部,我有几个控件需要在表单脏时显示保存对话框,即 form.$dirty = true。但是表单中有一些导航控件我不想弄脏表单。假设我无法将控件移出表单。
见: http: //plnkr.co/edit/bfig4B
如何使选择框不弄脏表单?
我在页面上有一个 ng 表单。在表单内部,我有几个控件需要在表单脏时显示保存对话框,即 form.$dirty = true。但是表单中有一些导航控件我不想弄脏表单。假设我无法将控件移出表单。
见: http: //plnkr.co/edit/bfig4B
如何使选择框不弄脏表单?
这是使用指令而不使用 $timeout 的@acacia 答案的一个版本。这将使您的控制器保持清洁。
.directive('noDirtyCheck', function() {
// Interacting with input elements having this directive won't cause the
// form to be marked dirty.
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$pristine = false;
}
}
});
然后在您的表单中使用它,如下所示:
<input type="text" name="foo" ng-model="x.foo" no-dirty-check>
我使用了@overthink 的解决方案,但遇到了@dmitankin 提到的问题。但是,我不想将处理程序附加到焦点事件。因此,相反,我努力覆盖 $pristine 属性本身并强制它始终返回 false。我最终使用了 IE8 及更低版本不支持的 Object.defineProperty。在那些旧版浏览器中有解决方法可以做到这一点,但我不需要它们,所以它们不是我下面解决方案的一部分:
(function () {
angular
.module("myapp")
.directive("noDirtyCheck", noDirtyCheck);
function noDirtyCheck() {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attrs, ctrl) {
var alwaysFalse = {
get: function () { return false; },
set: function () { }
};
Object.defineProperty(ctrl, '$pristine', alwaysFalse);
Object.defineProperty(ctrl, '$dirty', alwaysFalse);
}
};
}
})();
我也覆盖了 $dirty 所以它也不能被设置为脏。
仅在初始化时将 $pristine 属性设置为 false,直到您在表单上调用 $setPristine() 为止。然后您的控件将其 $pristine 恢复为 true 并且更改输入的值会使您的表单变脏。为避免这种情况,请将 $pristine 设置为焦点:
link: function(scope, elm, attrs, ctrl) {
elm.focus(function () {
ctrl.$pristine = false;
});
}
如果控件是原始的,Angular 只会将表单设置为脏。所以这里的诀窍是将控件上的 $pristine 设置为 false。您可以在控制器中超时执行此操作。
见: http: //plnkr.co/edit/by3qTM
这是我的最终答案。基本上,当与输入交互时,angular 会在内部调用NgModelController$setDirty()
的函数,所以只需覆盖它!
app.directive('noDirtyCheck', function() {
return {
restrict: 'A',
require: 'ngModel',
link: postLink
};
function postLink(scope, iElem, iAttrs, ngModelCtrl) {
ngModelCtrl.$setDirty = angular.noop;
}
})
我在该实现中遇到了一些问题,所以这是我的(更复杂):
app.directive('noDirtyCheck', [function () {
// Interacting with input elements having this directive won't cause the
// form to be marked dirty.
// http://stackoverflow.com/questions/17089090/prevent-input-from-setting-form-dirty-angularjs
return {
restrict: 'A',
require: ['^form', '^ngModel'],
link: function (scope, element, attrs, controllers) {
var form = controllers[0];
var currentControl = controllers[1];
var formDirtyState = false;
var manualFocus = false;
element.bind('focus',function () {
manualFocus = true;
if (form) {
window.console && console.log('Saving current form ' + form.$name + ' dirty status: ' + form.$dirty);
formDirtyState = form.$dirty; // save form's dirty state
}
});
element.bind('blur', function () {
if (currentControl) {
window.console && console.log('Resetting current control (' + currentControl.$name + ') dirty status to false (called from blur)');
currentControl.$dirty = false; // Remove dirty state but keep the value
if (!formDirtyState && form && manualFocus) {
window.console && console.log('Resetting ' + form.$name + ' form pristine state...');
form.$setPristine();
}
manualFocus = false;
// scope.$apply();
}
});
}
};
}]);
@overthink 的答案的变体,带有一些额外的验证,以及内联括号符号以防止缩小。
"use strict";
angular.module("lantern").directive("noDirtyCheck", [function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, elem, attrs, ngModelCtrl) {
if (!ngModelCtrl) {
return;
}
var clean = (ngModelCtrl.$pristine && !ngModelCtrl.$dirty);
if (clean) {
ngModelCtrl.$pristine = false;
ngModelCtrl.$dirty = true;
}
}
};
}]);