lordfpx/AB-formValidation

View on GitHub
index.js

Summary

Maintainability
C
1 day
Test Coverage
/*!
 * AB-formValidation
 */

var AB                = require('another-brick');
var abFieldValidation = require('./AB-fieldValidation');

'use strict';

var defaults = {
    classValid:       'is-valid',
    classInvalid:     'isnt-valid',
    classBtnDisabled: 'is-disabled',

    typing:         false,
    submitDisabled: true,

    validations: {
      badInput:        'error: badInput',
      patternMismatch: 'error: patternMismatch',
      rangeOverflow:   'error: rangeOverflow',
      rangeUnderflow:  'error: rangeUnderflow',
      stepMismatch:    'error: stepMismatch',
      tooLong:         'error: tooLong',
      tooShort:        'error: tooShort',
      typeMismatch:    'error: typeMismatch',
      valueMissing:    'error: valueMissing'
    }
  };

function FormValidation(el, options) {
  this.el = el;

  var dataOptions = window.AB.isJson(this.el.getAttribute('data-ab-form-validation')) ? JSON.parse(this.el.getAttribute('data-ab-form-validation')) : {};
  this.settings   = window.AB.extend(true, defaults, options, dataOptions);

  this.submitBtn  = this.el.querySelector('[data-ab-form-validation-submit]');
  this.isValid    = this.el.checkValidity(); // form status

  if (!this.submitBtn) {
    console.warn('The submit button is missing');
    return;
  }

  this._init();
}

FormValidation.prototype = {
  _init: function() {
    // prepare fields validation
    window.abFieldValidation(this.el, this.settings);

    // prepare form
    this.el.setAttribute('novalidate', 'novalidate');

    if (this.settings.submitDisabled && !this.isValid) {
      this.submitBtn.classList.add(this.settings.classBtnDisabled);
      this.submitBtn.disabled = true;
    }

    this._events();
  },

  _events: function() {
    this.el.addEventListener('submit', this._onSubmit.bind(this));
  },

  _onSubmit: function(e) {
    this._update(e);

    var fields = this.el.querySelectorAll('[data-ab-field-validation]');
    for (var i = 0, len = fields.length; i < len; i++) {
      fields[i].abFieldValidation.checkValidity('submit');
    }

    // trigger event for submit for external usage
    var event = new CustomEvent('submit.ab-formvalidation', {
      detail: {
        form: this.el,
        valid: this.isValid
      }
    });
    document.dispatchEvent(event);
  },

  // external usage to update form
  checkValidation: function() {
    this._update();
  },

  _update: function(e) {
    if (e && !this.isValid)
      e.preventDefault(); // prevent submitting

    this.isValid = this.el.checkValidity();

    if (this.isValid)
      this.setValid();
    else
      this.setInvalid();
  },

  setValid: function() {
    if (this.settings.submitDisabled) {
      this.submitBtn.classList.remove(this.settings.classBtnDisabled);
      this.submitBtn.disabled = false;
    }

    this.el.classList.remove(this.settings.classInvalid);
    this.el.classList.add(this.settings.classValid);
  },

  setInvalid: function() {
    if (this.settings.submitDisabled) {
      this.submitBtn.classList.add(this.settings.classBtnDisabled);
      this.submitBtn.disabled = true;
    }

    this.el.classList.add(this.settings.classInvalid);
    this.el.classList.remove(this.settings.classValid);
  }
};

window.abFormValidation = function(options) {
  var elements = document.querySelectorAll('[data-ab-form-validation]');
  for (var i = 0, len = elements.length; i < len; i++) {
    if (elements[i].abFormValidation) continue;
    elements[i].abFormValidation = new FormValidation(elements[i], options);
  }
};