mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-04-27 18:04:47 +00:00
feat(form): add ability to reset a form to pristine state
Retting a form to pristine state will cause all of the nested form and form controls to be recursively reset as well. Closes #856
This commit is contained in:
parent
96ed9ff59a
commit
733a97adf8
4 changed files with 165 additions and 2 deletions
|
|
@ -5,7 +5,8 @@ var nullFormCtrl = {
|
||||||
$addControl: noop,
|
$addControl: noop,
|
||||||
$removeControl: noop,
|
$removeControl: noop,
|
||||||
$setValidity: noop,
|
$setValidity: noop,
|
||||||
$setDirty: noop
|
$setDirty: noop,
|
||||||
|
$setPristine: noop
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -37,7 +38,8 @@ function FormController(element, attrs) {
|
||||||
var form = this,
|
var form = this,
|
||||||
parentForm = element.parent().controller('form') || nullFormCtrl,
|
parentForm = element.parent().controller('form') || nullFormCtrl,
|
||||||
invalidCount = 0, // used to easily determine if we are valid
|
invalidCount = 0, // used to easily determine if we are valid
|
||||||
errors = form.$error = {};
|
errors = form.$error = {},
|
||||||
|
controls = [];
|
||||||
|
|
||||||
// init state
|
// init state
|
||||||
form.$name = attrs.name;
|
form.$name = attrs.name;
|
||||||
|
|
@ -61,6 +63,8 @@ function FormController(element, attrs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
form.$addControl = function(control) {
|
form.$addControl = function(control) {
|
||||||
|
controls.push(control);
|
||||||
|
|
||||||
if (control.$name && !form.hasOwnProperty(control.$name)) {
|
if (control.$name && !form.hasOwnProperty(control.$name)) {
|
||||||
form[control.$name] = control;
|
form[control.$name] = control;
|
||||||
}
|
}
|
||||||
|
|
@ -73,6 +77,8 @@ function FormController(element, attrs) {
|
||||||
forEach(errors, function(queue, validationToken) {
|
forEach(errors, function(queue, validationToken) {
|
||||||
form.$setValidity(validationToken, true, control);
|
form.$setValidity(validationToken, true, control);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
arrayRemove(controls, control);
|
||||||
};
|
};
|
||||||
|
|
||||||
form.$setValidity = function(validationToken, isValid, control) {
|
form.$setValidity = function(validationToken, isValid, control) {
|
||||||
|
|
@ -120,6 +126,29 @@ function FormController(element, attrs) {
|
||||||
parentForm.$setDirty();
|
parentForm.$setDirty();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc function
|
||||||
|
* @name ng.directive:form.FormController#$setPristine
|
||||||
|
* @methodOf ng.directive:form.FormController
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Sets the form to its pristine state.
|
||||||
|
*
|
||||||
|
* This method can be called to remove the 'ng-dirty' class and set the form to its pristine
|
||||||
|
* state (ng-pristine class). This method will also propagate to all the controls contained
|
||||||
|
* in this form.
|
||||||
|
*
|
||||||
|
* Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
|
||||||
|
* saving or resetting it.
|
||||||
|
*/
|
||||||
|
form.$setPristine = function () {
|
||||||
|
element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
|
||||||
|
form.$dirty = false;
|
||||||
|
form.$pristine = true;
|
||||||
|
forEach(controls, function(control) {
|
||||||
|
control.$setPristine();
|
||||||
|
});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -978,6 +978,22 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||||
parentForm.$setValidity(validationErrorKey, isValid, this);
|
parentForm.$setValidity(validationErrorKey, isValid, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc function
|
||||||
|
* @name ng.directive:ngModel.NgModelController#$setPristine
|
||||||
|
* @methodOf ng.directive:ngModel.NgModelController
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Sets the control to its pristine state.
|
||||||
|
*
|
||||||
|
* This method can be called to remove the 'ng-dirty' class and set the control to its pristine
|
||||||
|
* state (ng-pristine class).
|
||||||
|
*/
|
||||||
|
this.$setPristine = function () {
|
||||||
|
this.$dirty = false;
|
||||||
|
this.$pristine = true;
|
||||||
|
$element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc function
|
* @ngdoc function
|
||||||
|
|
|
||||||
|
|
@ -430,4 +430,110 @@ describe('form', function() {
|
||||||
expect(doc).toBeDirty();
|
expect(doc).toBeDirty();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('$setPristine', function() {
|
||||||
|
|
||||||
|
it('should reset pristine state of form and controls', function() {
|
||||||
|
|
||||||
|
doc = $compile(
|
||||||
|
'<form name="testForm">' +
|
||||||
|
'<input ng-model="named1" name="foo">' +
|
||||||
|
'<input ng-model="named2" name="bar">' +
|
||||||
|
'</form>')(scope);
|
||||||
|
|
||||||
|
scope.$digest();
|
||||||
|
|
||||||
|
var form = doc,
|
||||||
|
formCtrl = scope.testForm,
|
||||||
|
input1 = form.find('input').eq(0),
|
||||||
|
input1Ctrl = input1.controller('ngModel'),
|
||||||
|
input2 = form.find('input').eq(1),
|
||||||
|
input2Ctrl = input2.controller('ngModel');
|
||||||
|
|
||||||
|
input1Ctrl.$setViewValue('xx');
|
||||||
|
input2Ctrl.$setViewValue('yy');
|
||||||
|
scope.$apply();
|
||||||
|
expect(form).toBeDirty();
|
||||||
|
expect(input1).toBeDirty();
|
||||||
|
expect(input2).toBeDirty();
|
||||||
|
|
||||||
|
formCtrl.$setPristine();
|
||||||
|
expect(form).toBePristine();
|
||||||
|
expect(formCtrl.$pristine).toBe(true);
|
||||||
|
expect(formCtrl.$dirty).toBe(false);
|
||||||
|
expect(input1).toBePristine();
|
||||||
|
expect(input1Ctrl.$pristine).toBe(true);
|
||||||
|
expect(input1Ctrl.$dirty).toBe(false);
|
||||||
|
expect(input2).toBePristine();
|
||||||
|
expect(input2Ctrl.$pristine).toBe(true);
|
||||||
|
expect(input2Ctrl.$dirty).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should reset pristine state of anonymous form controls', function() {
|
||||||
|
|
||||||
|
doc = $compile(
|
||||||
|
'<form name="testForm">' +
|
||||||
|
'<input ng-model="anonymous">' +
|
||||||
|
'</form>')(scope);
|
||||||
|
|
||||||
|
scope.$digest();
|
||||||
|
|
||||||
|
var form = doc,
|
||||||
|
formCtrl = scope.testForm,
|
||||||
|
input = form.find('input').eq(0),
|
||||||
|
inputCtrl = input.controller('ngModel');
|
||||||
|
|
||||||
|
inputCtrl.$setViewValue('xx');
|
||||||
|
scope.$apply();
|
||||||
|
expect(form).toBeDirty();
|
||||||
|
expect(input).toBeDirty();
|
||||||
|
|
||||||
|
formCtrl.$setPristine();
|
||||||
|
expect(form).toBePristine();
|
||||||
|
expect(formCtrl.$pristine).toBe(true);
|
||||||
|
expect(formCtrl.$dirty).toBe(false);
|
||||||
|
expect(input).toBePristine();
|
||||||
|
expect(inputCtrl.$pristine).toBe(true);
|
||||||
|
expect(inputCtrl.$dirty).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should reset pristine state of nested forms', function() {
|
||||||
|
|
||||||
|
doc = $compile(
|
||||||
|
'<form name="testForm">' +
|
||||||
|
'<div ng-form>' +
|
||||||
|
'<input ng-model="named" name="foo">' +
|
||||||
|
'</div>' +
|
||||||
|
'</form>')(scope);
|
||||||
|
|
||||||
|
scope.$digest();
|
||||||
|
|
||||||
|
var form = doc,
|
||||||
|
formCtrl = scope.testForm,
|
||||||
|
nestedForm = form.find('div'),
|
||||||
|
nestedFormCtrl = nestedForm.controller('form'),
|
||||||
|
nestedInput = form.find('input').eq(0),
|
||||||
|
nestedInputCtrl = nestedInput.controller('ngModel');
|
||||||
|
|
||||||
|
nestedInputCtrl.$setViewValue('xx');
|
||||||
|
scope.$apply();
|
||||||
|
expect(form).toBeDirty();
|
||||||
|
expect(nestedForm).toBeDirty();
|
||||||
|
expect(nestedInput).toBeDirty();
|
||||||
|
|
||||||
|
formCtrl.$setPristine();
|
||||||
|
expect(form).toBePristine();
|
||||||
|
expect(formCtrl.$pristine).toBe(true);
|
||||||
|
expect(formCtrl.$dirty).toBe(false);
|
||||||
|
expect(nestedForm).toBePristine();
|
||||||
|
expect(nestedFormCtrl.$pristine).toBe(true);
|
||||||
|
expect(nestedFormCtrl.$dirty).toBe(false);
|
||||||
|
expect(nestedInput).toBePristine();
|
||||||
|
expect(nestedInputCtrl.$pristine).toBe(true);
|
||||||
|
expect(nestedInputCtrl.$dirty).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,18 @@ describe('NgModelController', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('setPristine', function() {
|
||||||
|
|
||||||
|
it('should set control to its pristine state', function() {
|
||||||
|
ctrl.$setViewValue('edit');
|
||||||
|
expect(ctrl.$dirty).toBe(true);
|
||||||
|
expect(ctrl.$pristine).toBe(false);
|
||||||
|
|
||||||
|
ctrl.$setPristine();
|
||||||
|
expect(ctrl.$dirty).toBe(false);
|
||||||
|
expect(ctrl.$pristine).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('view -> model', function() {
|
describe('view -> model', function() {
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue