'use strict'; /** * @ngdoc object * @name angular.module.ng.$compileProvider.directive.form.FormController * * @property {boolean} $pristine True if user has not interacted with the form yet. * @property {boolean} $dirty True if user has already interacted with the form. * @property {boolean} $valid True if all of the containg forms and controls are valid. * @property {boolean} $invalid True if at least one containing control or form is invalid. * * @property {Object} $error Is an object hash, containing references to all invalid controls or * forms, where: * * - keys are validation tokens (error names) — such as `REQUIRED`, `URL` or `EMAIL`), * - values are arrays of controls or forms that are invalid with given error. * * @description * `FormController` keeps track of all its controls and nested forms as well as state of them, * such as being valid/invalid or dirty/pristine. * * Each {@link angular.module.ng.$compileProvider.directive.form form} directive creates an instance * of `FormController`. * */ FormController.$inject = ['name', '$element']; function FormController(name, element) { var form = this, parentForm = element.parent().inheritedData('$formController'), errors = form.$error = {}; // publish the form into scope name(this); if (parentForm) { parentForm.$addControl(form); } form.$addControl = function(control) { if (control.$name && !form.hasOwnProperty(control.$name)) { form[control.$name] = control; } } form.$removeControl = function(control) { if (control.$name && form[control.$name] === control) { delete form[control.$name]; } forEach(errors, cleanupControlErrors, control); }; form.$setValidity = function(validationToken, isValid, control) { if (isValid) { cleanupControlErrors(errors[validationToken], validationToken, control); if (equals(errors, {})) { form.$valid = true; form.$invalid = false; } } else { addControlError(validationToken, control); form.$valid = false; form.$invalid = true; } }; form.$setDirty = function() { form.$dirty = true; form.$pristine = false; } // init state form.$dirty = false; form.$pristine = true; form.$valid = true; form.$invalid = false; function cleanupControlErrors(queue, validationToken, control) { if (queue) { control = control || this; // so that we can be used in forEach; for (var i = 0, length = queue.length; i < length; i++) { if (queue[i] === control) { queue.splice(i, 1); if (!queue.length) { delete errors[validationToken]; if (parentForm) { parentForm.$setValidity(validationToken, true, form); } } } } } } function addControlError(validationToken, control) { var queue = errors[validationToken]; if (queue) { for (var i = 0, length = queue.length; i < length; i++) { if (queue[i] === control) { return; } } } else { errors[validationToken] = queue = []; if (parentForm) { parentForm.$setValidity(validationToken, false, form); } } queue.push(control); } } /** * @ngdoc directive * @name angular.module.ng.$compileProvider.directive.form * @restrict EA * * @description * Directive that instantiates * {@link angular.module.ng.$compileProvider.directive.form.FormController FormController}. * * If `name` attribute is specified, the form controller is published onto the current scope under * this name. * * # Alias: `ng-form` * * In angular forms can be nested. This means that the outer form is valid when all of the child * forms are valid as well. However browsers do not allow nesting of `