aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ng/directive/form.js33
-rw-r--r--src/ng/directive/input.js16
-rw-r--r--test/ng/directive/formSpec.js106
-rw-r--r--test/ng/directive/inputSpec.js12
4 files changed, 165 insertions, 2 deletions
diff --git a/src/ng/directive/form.js b/src/ng/directive/form.js
index 4f06f093..b4d500c6 100644
--- a/src/ng/directive/form.js
+++ b/src/ng/directive/form.js
@@ -5,7 +5,8 @@ var nullFormCtrl = {
$addControl: noop,
$removeControl: noop,
$setValidity: noop,
- $setDirty: noop
+ $setDirty: noop,
+ $setPristine: noop
};
/**
@@ -37,7 +38,8 @@ function FormController(element, attrs) {
var form = this,
parentForm = element.parent().controller('form') || nullFormCtrl,
invalidCount = 0, // used to easily determine if we are valid
- errors = form.$error = {};
+ errors = form.$error = {},
+ controls = [];
// init state
form.$name = attrs.name;
@@ -61,6 +63,8 @@ function FormController(element, attrs) {
}
form.$addControl = function(control) {
+ controls.push(control);
+
if (control.$name && !form.hasOwnProperty(control.$name)) {
form[control.$name] = control;
}
@@ -73,6 +77,8 @@ function FormController(element, attrs) {
forEach(errors, function(queue, validationToken) {
form.$setValidity(validationToken, true, control);
});
+
+ arrayRemove(controls, control);
};
form.$setValidity = function(validationToken, isValid, control) {
@@ -120,6 +126,29 @@ function FormController(element, attrs) {
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();
+ });
+ };
}
diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js
index e17c12b3..695ca88a 100644
--- a/src/ng/directive/input.js
+++ b/src/ng/directive/input.js
@@ -978,6 +978,22 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
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
diff --git a/test/ng/directive/formSpec.js b/test/ng/directive/formSpec.js
index 2fd55f60..9fe98570 100644
--- a/test/ng/directive/formSpec.js
+++ b/test/ng/directive/formSpec.js
@@ -430,4 +430,110 @@ describe('form', function() {
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);
+ });
+ });
});
diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js
index 01669b18..4dcb79a3 100644
--- a/test/ng/directive/inputSpec.js
+++ b/test/ng/directive/inputSpec.js
@@ -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() {