Form validation library Background:

After reading this thought provoking book I decided to write a small library as an exercise.

goog.require('goog.structs.Map');


var MyModule = {};

MyModule.FormHelper = {
  /** @type {?Element} */
  form: null,
  /** @type {goog.structs.Map&lt;string, string&gt;} */
  errors: {},

  /** @param {!Element} element */
  init: function(formElement) {
    this.form = formElement;
  },

  /**
   * @param {!Element} element
   * @return {!Array&lt;goog.structs.Map&lt;string, Object&gt;&gt;}
   */
  getElementAttributes: function(element) {
    if (!element) return [];
    return [].slice.call(element.attributes).map(function(attr) {
      return {[attr.name]: attr.value};
    });
  },

  /**
   * @param {string} filterOn
   * @return {!Array&lt;!Element&gt;}
   */
  filterElements: function(filterOn) {
    return [].slice.call(this.form.elements).filter(function(element) {
      return element.hasAttribute(filterOn);
    });
  }
};

MyModule.Form = Object.create(MyModule.FormHelper);

MyModule.Form.validate = function() {
  /** @type {!Array&lt;!Element&gt;} */
  var elements = this.getRequiredElements();
  elements.reduce(function(map, element) {
    if (element.value == '') {
      map[element.name] = 'Required field cannot be empty';
    }
    return map;
  }, this.errors);
};

MyModule.Form.getRequiredElements = function() {
  return this.filterElements('required');
};

MyModule.createForm = function(name) {
  /** @type {!Element} */
  var formElement = document.forms[name];
  if (!formElement) {
    throw new Error('Form not found.');
  }
  var form = Object.create(MyModule.Form);
  form.init(formElement);
  return form;
};

var contactForm;
var callback = function(e) {
  e.preventDefault()
  contactForm.validate();
  console.log(contactForm.errors);
}

window.onload = function () {
  contactForm = MyModule.createForm('ContactForm');
  contactForm.form.addEventListener("submit", callback, false);  //Modern browsers
}


I am using Google closure for type checking and advance code optimizations.

I want to check if I am following a good object oriented design and practices?

Update 1

;(function(global, doc, lib) {
  var Form = {};

  Form.create = function(name) {
    var form = doc.forms[name];
    if (!form) {
      throw new Error('Form not found.');
    }
    this.formElement = form;
  };

  Form.elements = function() {
    return this.formElement.elements;
  };

  Form.filter = function(attr) {
    return [].slice.call(this.elements()).filter(function(element) {
      return element.hasAttribute(attr);
    });
  };

  Form.getAttributes = function(element) {
    if (!element) return [];
    return [].slice.call(element.attributes).map(function(attr) {
      return {[attr.name]: attr.value};
    });
  };

  Form.validate = function(formName) {
    var elements = this.filter('required');
    elements.reduce(function(error, element) {
      if (element.value == '') {
        error[element.name] = 'Required field cannot be empty';
      }
      return error;
    }, this.errors);
  };

  lib.validate = function(formName) {
    var form = Object.create(Form);
    form.create(formName);
    form.errors = [];
    form.validate();
    return form;
  };

})(window, document, window.lib || (window.lib = {}));

window.onload = function() {
  console.log(lib);
  console.log(lib.validate('foo').errors);
};
Global variables

I know this isn't part of the module and probably just throwaway code, but you should restructure the module usage to avoid making global variables contactForm and callback:

    window.onload = function () {
      var contactForm = MyModule.createForm('ContactForm');
      contactForm.form.addEventListener("submit", function onSubmit(e) {
        e.preventDefault()
        contactForm.validate();
        console.log(contactForm.errors);
      }, false);  //Modern browsers
    }


Organization of properties between prototypes

I'm not sure why you'd divide up methods and properties between FormHelper and Form, as they seem to perform very similar functionality. I'd combine them into a single Form object; that's the only prototype you need.

This may seem too simple, but your module solves a simple problem. A more complicated module that would benefit from delegation between multiple prototypes would be one that has multiple types of Element prototypes, with some validation functions shared between Elements and some specific to particular types.

form prototype property

I don't think you need/want the form: null property on the prototype object. Even though init is a method of the prototype, it's assigning form to the base object (also named form) that exists in the submit handler, and that's what you want - a shared form property would make multiple Forms impossible.

Also, a subjective point: I'd rename this property to formElement or just element, since there are too many forms and Forms running around this code.



I hope this helps! Kyle Simpson's YDKJS books made me think as well, and with ES6 classes growing more common every day, I often wonder how this explicitly prototype-based JavaScript style can coexist with the classes Simpson discredited.