From 770b30d6a710b7dfddf39be5a9d1577d7fdaa560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Andr=C3=A9s=20Gallinal?= Date: Mon, 30 Dec 2013 11:52:25 -0300 Subject: [PATCH 1/2] feat(form): $submitted state Added new state to form: - it sets to true when form is submitted - it sets back to false when $setPristine is called on the form --- src/ng/directive/form.js | 31 +++++++++++++++++++++++++++---- test/ng/directive/formSpec.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/ng/directive/form.js b/src/ng/directive/form.js index 64000220c1b2..9b390f131a94 100644 --- a/src/ng/directive/form.js +++ b/src/ng/directive/form.js @@ -1,13 +1,18 @@ 'use strict'; -/* global -nullFormCtrl */ +/* global + -nullFormCtrl, + -SUBMITTED_CLASS +*/ var nullFormCtrl = { $addControl: noop, $removeControl: noop, $setValidity: noop, $setDirty: noop, - $setPristine: noop -}; + $setPristine: noop, + $setSubmitted: noop +}, +SUBMITTED_CLASS = 'ng-submitted'; /** * @ngdoc type @@ -60,6 +65,7 @@ function FormController(element, attrs, $scope, $animate) { form.$pristine = true; form.$valid = true; form.$invalid = false; + form.$submitted = false; parentForm.$addControl(form); @@ -230,15 +236,30 @@ function FormController(element, attrs, $scope, $animate) { form.$setPristine = function () { $animate.removeClass(element, DIRTY_CLASS); $animate.addClass(element, PRISTINE_CLASS); + $animate.removeClass(element, SUBMITTED_CLASS); form.$dirty = false; form.$pristine = true; + form.$submitted = false; forEach(controls, function(control) { control.$setPristine(); }); }; + + /** + * @ngdoc function + * @name ng.directive:form.FormController#$setSubmitted + * @methodOf ng.directive:form.FormController + * + * @description + * Sets the form to its submitted state. + */ + form.$setSubmitted = function () { + element.addClass(element, SUBMITTED_CLASS); + form.$submitted = true; + parentForm.$setSubmitted(); + }; } - /** * @ngdoc directive * @name ngForm @@ -287,6 +308,7 @@ function FormController(element, attrs, $scope, $animate) { * - `ng-invalid` is set if the form is invalid. * - `ng-pristine` is set if the form is pristine. * - `ng-dirty` is set if the form is dirty. + * - `ng-submitted` is set if the form was submitted. * * Keep in mind that ngAnimate can detect each of these classes when added and removed. * @@ -422,6 +444,7 @@ var formDirectiveFactory = function(isNgForm) { var handleFormSubmission = function(event) { scope.$apply(function() { controller.$commitViewValue(); + controller.$setSubmitted(); }); event.preventDefault diff --git a/test/ng/directive/formSpec.js b/test/ng/directive/formSpec.js index f43c35a3713f..0db1b2bbd75f 100644 --- a/test/ng/directive/formSpec.js +++ b/test/ng/directive/formSpec.js @@ -404,6 +404,9 @@ describe('form', function() { child.$setDirty(); expect(parent.$dirty).toBeTruthy(); + + child.$setSubmitted(); + expect(parent.$submitted).toBeTruthy(); }); @@ -681,6 +684,33 @@ describe('form', function() { expect(nestedInputCtrl.$dirty).toBe(false); }); }); + + describe('$setSubmitted', function() { + beforeEach(function() { + doc = $compile( + '
' + + '' + + '' + + '
')(scope); + + scope.$digest(); + }); + + it('should not init in submitted state', function() { + expect(scope.form.$submitted).toBe(false); + }); + + it('should be in submitted state when submitted', function() { + browserTrigger(doc, 'submit'); + expect(scope.form.$submitted).toBe(true); + }); + + it('should revert submitted back to false when $setPristine is called on the form', function() { + scope.form.$submitted = true + scope.form.$setPristine(); + expect(scope.form.$submitted).toBe(false); + }); + }); }); describe('form animations', function() { From e704fc937732b688bf7bd514eeb663cb45df5178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Andr=C3=A9s=20Gallinal?= Date: Sat, 19 Jul 2014 17:51:39 -0300 Subject: [PATCH 2/2] fix ngForm: implement what @Matsko suggested use $animate.setClass in form.$setPristine to just use one animation use $animate.addClass in form.$setSubmitted Closes #8056 --- src/ng/directive/form.js | 10 ++++------ test/ng/directive/formSpec.js | 18 +++++++++--------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/ng/directive/form.js b/src/ng/directive/form.js index 9b390f131a94..8f1508120902 100644 --- a/src/ng/directive/form.js +++ b/src/ng/directive/form.js @@ -1,6 +1,6 @@ 'use strict'; -/* global +/* global -nullFormCtrl, -SUBMITTED_CLASS */ @@ -234,9 +234,7 @@ function FormController(element, attrs, $scope, $animate) { * saving or resetting it. */ form.$setPristine = function () { - $animate.removeClass(element, DIRTY_CLASS); - $animate.addClass(element, PRISTINE_CLASS); - $animate.removeClass(element, SUBMITTED_CLASS); + $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS); form.$dirty = false; form.$pristine = true; form.$submitted = false; @@ -244,7 +242,7 @@ function FormController(element, attrs, $scope, $animate) { control.$setPristine(); }); }; - + /** * @ngdoc function * @name ng.directive:form.FormController#$setSubmitted @@ -254,7 +252,7 @@ function FormController(element, attrs, $scope, $animate) { * Sets the form to its submitted state. */ form.$setSubmitted = function () { - element.addClass(element, SUBMITTED_CLASS); + $animate.addClass(element, SUBMITTED_CLASS); form.$submitted = true; parentForm.$setSubmitted(); }; diff --git a/test/ng/directive/formSpec.js b/test/ng/directive/formSpec.js index 0db1b2bbd75f..21e21f3234dd 100644 --- a/test/ng/directive/formSpec.js +++ b/test/ng/directive/formSpec.js @@ -404,7 +404,7 @@ describe('form', function() { child.$setDirty(); expect(parent.$dirty).toBeTruthy(); - + child.$setSubmitted(); expect(parent.$submitted).toBeTruthy(); }); @@ -684,7 +684,7 @@ describe('form', function() { expect(nestedInputCtrl.$dirty).toBe(false); }); }); - + describe('$setSubmitted', function() { beforeEach(function() { doc = $compile( @@ -695,18 +695,18 @@ describe('form', function() { scope.$digest(); }); - + it('should not init in submitted state', function() { expect(scope.form.$submitted).toBe(false); }); - + it('should be in submitted state when submitted', function() { browserTrigger(doc, 'submit'); expect(scope.form.$submitted).toBe(true); }); it('should revert submitted back to false when $setPristine is called on the form', function() { - scope.form.$submitted = true + scope.form.$submitted = true; scope.form.$setPristine(); expect(scope.form.$submitted).toBe(false); }); @@ -716,9 +716,10 @@ describe('form', function() { describe('form animations', function() { beforeEach(module('ngAnimateMock')); - function assertValidAnimation(animation, event, className) { + function assertValidAnimation(animation, event, classNameAdded, classNameRemoved) { expect(animation.event).toBe(event); - expect(animation.args[1]).toBe(className); + expect(animation.args[1]).toBe(classNameAdded); + expect(animation.args[2]).toBe(classNameRemoved); } var doc, scope, form; @@ -771,8 +772,7 @@ describe('form animations', function() { form.$setPristine(); - assertValidAnimation($animate.queue[0], 'removeClass', 'ng-dirty'); - assertValidAnimation($animate.queue[1], 'addClass', 'ng-pristine'); + assertValidAnimation($animate.queue[0], 'setClass', 'ng-pristine', 'ng-dirty ng-submitted'); })); it('should trigger custom errors as addClass/removeClass when invalid/valid', inject(function($animate) {