I have an ng form on a page. Inside the form I have several controls which need to display a save dialog when the form is dirty, ie form.$dirty = true. However there are some navigation controls in the form I don't want to dirty the form. Assume I can't move the control out of the form.
我在页面上有一个表格。在表单内部,我有几个控件,当表单很脏时需要显示一个保存对话框,即表单。$ dirty = true。但是,我不希望弄脏表单的形式有一些导航控件。假设我无法将控件移出表单。
see: http://plnkr.co/edit/bfig4B
请参阅:http://plnkr.co/edit/bfig4B
How do I make the select box not dirty the form?
如何使表单中的选择框不脏?
7 个解决方案
#1
25
Here's a version of @acacia's answer using a directive and not using $timeout. This will keep your controllers cleaner.
这是使用指令而不使用$ 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;
}
}
});
Then use it in your form like so:
然后在您的表单中使用它,如下所示:
<input type="text" name="foo" ng-model="x.foo" no-dirty-check>
#2
12
Setting the $pristine property to false, only when initializing, works until you call $setPristine() on the form. Then your control has its $pristine back to true and changing the input's value would make your form dirty. To avoid that, set the $pristine on focus:
将$ pristine属性设置为false,仅在初始化时才有效,直到您在窗体上调用$ setPristine()为止。然后你的控件让它的$ pristine回到true,改变输入的值会使你的表单变脏。为避免这种情况,请将$ pristine设置为焦点:
link: function(scope, elm, attrs, ctrl) {
elm.focus(function () {
ctrl.$pristine = false;
});
}
#3
12
I used @overthink's solution, but ran into the problem mentioned by @dmitankin. However, I didn't want to attach a handler to the focus event. So instead, I endeavored to override the $pristine property itself and force it to return false always. I ended up using Object.defineProperty which is not supported in IE8 and below. There are workarounds to do this in those legacy browsers, but I didn't need them, so they are not part of my solution below:
我使用了@ 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);
}
};
}
})();
I am also overriding $dirty so it can't be set as dirty either.
我也凌驾于$脏,所以它也不能设置为脏。
#4
7
Angular only sets the form dirty if the control is pristine. So the trick here is to set $pristine on the control to false. You can do it in a timeout in the controller.
如果控件是原始的,Angular仅将表单设置为脏。所以这里的诀窍是将控件上的$ pristine设置为false。您可以在控制器中超时执行此操作。
see: http://plnkr.co/edit/by3qTM
请参阅:http://plnkr.co/edit/by3qTM
#5
0
A variation on @overthink's answer with some additional validation, and inline bracket notation to protect against minification.
@ overthink的答案的变体与一些额外的验证和内联括号表示法,以防止缩小。
"use strict";
angular.module("*").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
I ran into some problems with that implementation, so here is mine (more complex):
我遇到了一些实现问题,所以这是我的(更复杂):
app.directive('noDirtyCheck', [function () {
// Interacting with input elements having this directive won't cause the
// form to be marked dirty.
// http://*.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();
}
});
}
};
}]);
#7
0
This is my final answer. Basically angular internally calls the $setDirty()
function of the NgModelController when the input is interacted with, so just override that!
这是我的最终答案。当输入与之交互时,基本上angular会内部调用NgModelController的$ setDirty()函数,所以只需覆盖它!
app.directive('noDirtyCheck', function() {
return {
restrict: 'A',
require: 'ngModel',
link: postLink
};
function postLink(scope, iElem, iAttrs, ngModelCtrl) {
ngModelCtrl.$setDirty = angular.noop;
}
})
#1
25
Here's a version of @acacia's answer using a directive and not using $timeout. This will keep your controllers cleaner.
这是使用指令而不使用$ 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;
}
}
});
Then use it in your form like so:
然后在您的表单中使用它,如下所示:
<input type="text" name="foo" ng-model="x.foo" no-dirty-check>
#2
12
Setting the $pristine property to false, only when initializing, works until you call $setPristine() on the form. Then your control has its $pristine back to true and changing the input's value would make your form dirty. To avoid that, set the $pristine on focus:
将$ pristine属性设置为false,仅在初始化时才有效,直到您在窗体上调用$ setPristine()为止。然后你的控件让它的$ pristine回到true,改变输入的值会使你的表单变脏。为避免这种情况,请将$ pristine设置为焦点:
link: function(scope, elm, attrs, ctrl) {
elm.focus(function () {
ctrl.$pristine = false;
});
}
#3
12
I used @overthink's solution, but ran into the problem mentioned by @dmitankin. However, I didn't want to attach a handler to the focus event. So instead, I endeavored to override the $pristine property itself and force it to return false always. I ended up using Object.defineProperty which is not supported in IE8 and below. There are workarounds to do this in those legacy browsers, but I didn't need them, so they are not part of my solution below:
我使用了@ 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);
}
};
}
})();
I am also overriding $dirty so it can't be set as dirty either.
我也凌驾于$脏,所以它也不能设置为脏。
#4
7
Angular only sets the form dirty if the control is pristine. So the trick here is to set $pristine on the control to false. You can do it in a timeout in the controller.
如果控件是原始的,Angular仅将表单设置为脏。所以这里的诀窍是将控件上的$ pristine设置为false。您可以在控制器中超时执行此操作。
see: http://plnkr.co/edit/by3qTM
请参阅:http://plnkr.co/edit/by3qTM
#5
0
A variation on @overthink's answer with some additional validation, and inline bracket notation to protect against minification.
@ overthink的答案的变体与一些额外的验证和内联括号表示法,以防止缩小。
"use strict";
angular.module("*").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
I ran into some problems with that implementation, so here is mine (more complex):
我遇到了一些实现问题,所以这是我的(更复杂):
app.directive('noDirtyCheck', [function () {
// Interacting with input elements having this directive won't cause the
// form to be marked dirty.
// http://*.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();
}
});
}
};
}]);
#7
0
This is my final answer. Basically angular internally calls the $setDirty()
function of the NgModelController when the input is interacted with, so just override that!
这是我的最终答案。当输入与之交互时,基本上angular会内部调用NgModelController的$ setDirty()函数,所以只需覆盖它!
app.directive('noDirtyCheck', function() {
return {
restrict: 'A',
require: 'ngModel',
link: postLink
};
function postLink(scope, iElem, iAttrs, ngModelCtrl) {
ngModelCtrl.$setDirty = angular.noop;
}
})