netceteragroup/valdr

View on GitHub
src/core/valdrFormGroup-directive.js

Summary

Maintainability
B
6 hrs
Test Coverage
/**
 * This directive adds the validity state to a form group element surrounding valdr validated input fields.
 * If valdr-messages is loaded, it also adds the validation messages as last element to the element this this
 * directive is applied on.
 */
var valdrFormGroupDirectiveDefinition =
  ['valdrClasses', 'valdrConfig', function (valdrClasses, valdrConfig) {
    return  {
      restrict: 'EA',
      link: function (scope, element) {
        if (valdrConfig.addFormGroupClass) {
          element.addClass(valdrClasses.formGroup);
        }
      },
      controller: ['$scope', '$element', function ($scope, $element) {

        var formItems = [],
          messageElements = {};

        /**
         * Checks the state of all valdr validated form items below this element.
         * @returns {Object} an object containing the states of all form items in this form group
         */
        var getFormGroupState = function () {

          var formGroupState = {
            // true if an item in this form group is currently dirty, touched and invalid
            invalidDirtyTouchedGroup: false,
            // true if all form items in this group are currently valid
            valid: true,
            // contains the validity states of all form items in this group
            itemStates: []
          };

          angular.forEach(formItems, function (formItem) {
            if (formItem.$touched && formItem.$dirty && formItem.$invalid) {
              formGroupState.invalidDirtyTouchedGroup = true;
            }

            if (formItem.$invalid) {
              formGroupState.valid = false;
            }

            var itemState = {
              name: formItem.$name,
              touched: formItem.$touched,
              dirty: formItem.$dirty,
              valid: formItem.$valid
            };

            formGroupState.itemStates.push(itemState);
          });

          return formGroupState;
        };

        /**
         * Updates the classes on this element and the valdr message elements based on the validity states
         * of the items in this form group.
         * @param formGroupState the current state of this form group and its items
         */
        var updateClasses = function (formGroupState) {
          // form group state
          $element.toggleClass(valdrClasses.invalidDirtyTouchedGroup, formGroupState.invalidDirtyTouchedGroup);
          $element.toggleClass(valdrClasses.valid, formGroupState.valid);
          $element.toggleClass(valdrClasses.invalid, !formGroupState.valid);

          // valdr message states
          angular.forEach(formGroupState.itemStates, function (itemState) {
            var messageElement = messageElements[itemState.name];
            if (messageElement) {
              messageElement.toggleClass(valdrClasses.valid, itemState.valid);
              messageElement.toggleClass(valdrClasses.invalid, !itemState.valid);
              messageElement.toggleClass(valdrClasses.dirty, itemState.dirty);
              messageElement.toggleClass(valdrClasses.pristine, !itemState.dirty);
              messageElement.toggleClass(valdrClasses.touched, itemState.touched);
              messageElement.toggleClass(valdrClasses.untouched, !itemState.touched);
            }
          });
        };

        $scope.$watch(getFormGroupState, updateClasses, true);

        this.addFormItem = function (ngModelController) {
          formItems.push(ngModelController);
        };

        this.removeFormItem = function (ngModelController) {
          var index = formItems.indexOf(ngModelController);
          if (index >= 0) {
            formItems.splice(index, 1);
          }
        };

        this.addMessageElement = function (ngModelController, messageElement) {
          $element.append(messageElement);
          messageElements[ngModelController.$name] = messageElement;
        };

        this.removeMessageElement = function (ngModelController) {
          if (messageElements[ngModelController.$name]) {
            messageElements[ngModelController.$name].remove();
            delete messageElements[ngModelController.$name];
          }
        };

      }]
    };
  }];

angular.module('valdr')
  .directive('valdrFormGroup', valdrFormGroupDirectiveDefinition);