diff --git a/src/ng/directive/form.js b/src/ng/directive/form.js index 64000220c1b2..8f1508120902 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); @@ -228,16 +234,29 @@ function FormController(element, attrs, $scope, $animate) { * saving or resetting it. */ form.$setPristine = function () { - $animate.removeClass(element, DIRTY_CLASS); - $animate.addClass(element, PRISTINE_CLASS); + $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + 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 () { + $animate.addClass(element, SUBMITTED_CLASS); + form.$submitted = true; + parentForm.$setSubmitted(); + }; +} /** * @ngdoc directive @@ -287,6 +306,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 +442,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..21e21f3234dd 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,14 +684,42 @@ 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() { 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; @@ -741,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) {