我在页面上有一个表格。在表单内部,我有几个控件,当表单很脏时需要显示一个保存对话框,即表单。$ dirty = true。但是,我不希望弄脏表单的形式有一些导航控件。假设我无法将控件移出表单。
请参阅:http://plnkr.co/edit/bfig4B
如何使表格中的选择框不变脏?
答案 0 :(得分:25)
这是使用指令而不使用$ 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>
答案 1 :(得分:13)
我使用了@ overthink的解决方案,但遇到了@dmitankin提到的问题。但是,我不想将处理程序附加到焦点事件。所以相反,我努力覆盖$ pristine属性本身并强制它始终返回false。我最终使用了IE8及以下版本不支持的Object.defineProperty。在这些旧版浏览器中有workarounds来执行此操作,但我不需要它们,因此它们不属于我的解决方案:
(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,所以它也不能设置为脏。
答案 2 :(得分:12)
将$ pristine属性设置为false,仅在初始化时才有效,直到您在窗体上调用$ setPristine()为止。然后你的控件将其原始状态恢复为真,并且更改输入的值将使您的表单变脏。 为避免这种情况,请将$ pristine设置为焦点:
link: function(scope, elm, attrs, ctrl) {
elm.focus(function () {
ctrl.$pristine = false;
});
}
答案 3 :(得分:7)
如果控件是原始的,则Angular仅将表单设置为脏。所以这里的诀窍是将控件上的$ pristine设置为false。您可以在控制器中超时执行此操作。
答案 4 :(得分:1)
这是我的最终答案。当输入与之交互时,基本上angular会在内部调用 NgModelController 的$setDirty()
函数,所以只需覆盖它!
app.directive('noDirtyCheck', function() {
return {
restrict: 'A',
require: 'ngModel',
link: postLink
};
function postLink(scope, iElem, iAttrs, ngModelCtrl) {
ngModelCtrl.$setDirty = angular.noop;
}
})
答案 5 :(得分:0)
@ 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;
}
}
};
}]);
答案 6 :(得分:0)
我遇到了一些实现问题,所以这是我的(更复杂):
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();
}
});
}
};
}]);
&#13;