How to reset custom input directive and its parent form to $pristine
As of Angular 1.3.x, there is no built-in solution.
form.$setPristine()
sets pristine on all its child controls. (link to code)
ngModel.$setPristine()
only sets $pristine on itself (link to code)
One way to solve this is to create a directive that lives alongside a form
directive and hijacks form.$setDirty
to track dirty controls count. This is probably best done in a pre-link phase (i.e. before child controls start registering themselves).
app.directive("pristinableForm", function() {
return {
restrict: "A",
require: ["pristinableForm", "form"],
link: function(scope, element, attrs, ctrls) {
var me = ctrls[0],
form = ctrls[1];
me.form = form;
me.dirtyCounter = 0;
var formSetDirtyFn = form.$setDirty;
form.$setDirty = function() {
me.dirtyCounter++;
formSetDirtyFn();
};
},
controller: function() {
this.$notifyPristine = function() {
if (this.dirtyCounter === 0) return;
if (this.dirtyCounter === 1) {
this.dirtyCounter = 0;
if (this.form) this.form.$setPristine();
} else {
this.dirtyCounter--;
}
};
}
};
});
Then, the custom input directive needs to require: ["ngModel", "^pristinableForm"]
and call pristinableForm.$notifyPristine()
in its reset function:
scope.reset = function(){
if (ngModel.$dirty){
scope.counter = original;
ngModel.$setViewValue(scope.counter);
ngModel.$setPristine();
pristinableForm.$notifyPristine();
}
};
The usage is:
<div ng-form="form" pristinable-form>
<counter ng-model="count1"></counter>
<counter ng-model="count2"></counter>
<input ng-model="foo" name="anotherControl">
</div>
Related videos on Youtube
New Dev
Updated on June 04, 2022Comments
-
New Dev about 2 years
I've implemented a custom input directive -
counter
with a reset capability. The directive hasrequire: "ngModel"
.I am resetting the pristine state of the directive's
ngModel
with$setPristine()
. Unlike$setDirty()
,$setPristine()
does not touch the$pristine
state of the parent form.Q: How do I "notify" the parent form that this directive is no longer "dirty", such that the parent form could have its
$pristine
state reset?Bear in mind that just calling
form.$setPristine()
is not enough as there may be other "dirty" controls in the form, which my directive wouldn't (and shouldn't) know about.This is the directive's link function:
link: function(scope, element, attrs, ngModel){ var original; ngModel.$render = function(){ original = scope.counter = ngModel.$viewValue; }; scope.up = function(){ ngModel.$setViewValue(++scope.counter); }; scope.reset = function(){ scope.counter = original; ngModel.$setViewValue(scope.counter); ngModel.$setPristine(); // this sets $pristine on the directive, but not the form }; }
And here's how it is used:
<div ng-form="form"> <counter ng-model="count"></counter> </div>
-
New Dev over 9 yearsThanks for the help, but I explicitly stated that just calling
$setPristine()
on the form does not cut it, as the form may have other child controls that may be dirty. Also, the best way to do so would be torequire: "^form"
, rather than assume thatscope.form
exists. -
MamaWalter over 9 yearsok i think i understand, not sure there is built-in solution for that.
-
New Dev over 9 yearsI've answered my own question, but this is along the lines of what I am thinking of doing, except in your solution you are making an assumption about
form
existing on the scope. A directive's aim is to be re-usable, so it should not know in what form it resides. -
Naomi over 6 yearsSounds a bit too complex to my taste. Can you please check my related question stackoverflow.com/questions/48528957/…