DEV Community

sakethk
sakethk

Posted on • Updated on

Javascript form validator

Here we are going to build a form validator class it will expose four methods forField, addRule, validate and required.

forField

This method will take field name as argument which we want to validate and returns an current object.

addRule

This method will take 3 arguments (fieldName, conditionMethod, failureMessage) first argument is optional if we didn't pass fieldName it will add rules to the current field which we set using forField.

validate

validate method will take JSON as object, key is field name and value is field value. It will validate based on rules returns true if all are valid else it will return error message.

required

This method will add required rules for current field

Create a file name it validator.js

Creating Validator class

class Validator{
}
Enter fullscreen mode Exit fullscreen mode

we need to add rules object for validator class

 rules = {}
Enter fullscreen mode Exit fullscreen mode

next we need to add setField and setRule methods to Validator class

  setFeild(name) {
    this.feild = name;
    return this;
  }

  setRule(...args) {
    if (this.rules[this.feild])
      this.rules[this.feild].push({ rule: args[0], errMsg: args[1] });
    else this.rules[this.feild] = [{ rule: args[0], errMsg: args[1] }];
  }
Enter fullscreen mode Exit fullscreen mode

Now Validator class will be like this

class Validator {
  rules = {};

  setField(name) {
    this.field = name;
    return this;
  }

  setRule(...args) {
    if (this.rules[this.field])
      this.rules[this.field].push({ rule: args[0], errMsg: args[1] });
    else this.rules[this.field] = [{ rule: args[0], errMsg: args[1] }];
  }
}
Enter fullscreen mode Exit fullscreen mode

Adding addField method to validator class

Validator.prototype.forField = function (field) {
  this.setField(field);
  return this;
};
Enter fullscreen mode Exit fullscreen mode

we need two helper functions _addRule and clone

const _addRule = (obj, ...args) => {
  if (args.length === 3) {
    obj.setField(args[0]);
    args.shift();
  }
  obj.setRule(...args);
  return clone(obj);
};

function clone(obj) {
  return Object.create(
    Object.getPrototypeOf(obj),
    Object.getOwnPropertyDescriptors(obj)
  );
}
Enter fullscreen mode Exit fullscreen mode

Adding addRule method to validator class

Validator.prototype.addRule = function (...args) {
  return _addRule(this, ...args);
};
Enter fullscreen mode Exit fullscreen mode

Adding addRule metohod to validator class

Validator.prototype.required = function () {
  const isEmpty = e => !!e
  const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)
  this.setRule(isEmpty, capitalize(this.field) + " is required")
    return this;
};
Enter fullscreen mode Exit fullscreen mode

Adding validate method to validator class

Validator.prototype.validate = function (object) {
  const validationFields = Object.keys(this.rules);
  const errorResponses = {};
  let success = true;
  validationFields.forEach((item) => {
    const validation = this.rules[item].reduce((acc, e) => {
      if (!e.rule(object[item] || "")) {
        success = false;
        acc.push(e.errMsg);
      }
      return acc;
    }, []);

    if (validation.length > 0) errorResponses[item] = validation;
  });

  return {
    success,
    errors: !success ? { ...errorResponses } : {},
  };
};
Enter fullscreen mode Exit fullscreen mode

Finally your validator.js file will be like this

class Validator {
  rules = {};

  setField(name) {
    this.field = name;
    return this;
  }

  setRule(...args) {
    if (this.rules[this.field])
      this.rules[this.field].push({ rule: args[0], errMsg: args[1] });
    else this.rules[this.field] = [{ rule: args[0], errMsg: args[1] }];
  }
}

Validator.prototype.forField = function (field) {
  this.setField(field);
  return this;
};

const _addRule = (obj, ...args) => {
  if (args.length === 3) {
    obj.setField(args[0]);
    args.shift();
  }
  obj.setRule(...args);
  return clone(obj);
};

function clone(obj) {
  return Object.create(
    Object.getPrototypeOf(obj),
    Object.getOwnPropertyDescriptors(obj)
  );
}

Validator.prototype.addRule = function (...args) {
  return _addRule(this, ...args);
};

Validator.prototype.required = function () {
  const isEmpty = (e) => !!e;
  const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
  this.setRule(isEmpty, capitalize(this.field) + " is required");
  return this;
};

Validator.prototype.validate = function (object) {
  const validationFields = Object.keys(this.rules);
  const errorResponses = {};
  let success = true;
  validationFields.forEach((item) => {
    const validation = this.rules[item].reduce((acc, e) => {
      if (!e.rule(object[item] || "")) {
        success = false;
        acc.push(e.errMsg);
      }
      return acc;
    }, []);

    if (validation.length > 0) errorResponses[item] = validation;
  });

  return {
    success,
    errors: !success ? { ...errorResponses } : {},
  };
};
Enter fullscreen mode Exit fullscreen mode

Working with Validator class

create a file name it main.js and add few validation functions

const isNumber = e => !isNaN(e)
const isStrType = e => typeof e === 'string'
const lengthGtFive = e => e.length > 5
const lengthEqTen = e => e.length === 10
Enter fullscreen mode Exit fullscreen mode

Now add the following code to run our Validator

const formValidator = new Validator();
const nameRules = formValidator.forField("name").addRule(lengthGtFive, 'Name Should have atleast 6 letters').required()
const phoneNumberRules = formValidator.addRule('mobile', isNumber, 'Mobile number should only have numbers')
nameRules.addRule(isStrType, 'Name Should be alphabets')
phoneNumberRules.addRule(lengthEqTen, 'Mobile number should have 10 numbers')

//Success Case
formValidator.validate({
  name: "PERSON NAME",
  mobile: "1234567890",
});

/*output
{ success: true, errors: {} }
*/


//Negative Case 1
formValidator.validate({
  name: "PERSO",
  mobile: "1234567890",
});

/*output
{
  success: false,
  errors: { name: [ 'Name Should have atleast 6 letters' ] }
}
*/

//Negative Case 2
formValidator.validate({
  name: "PERSON",
  mobile: "jnlfne",
});

/*output
{
  success: false,
  errors: {
    mobile: [
      'Mobile number should only have numbers',
      'Mobile number should have 10 numbers'
    ]
  }
}
*/
Enter fullscreen mode Exit fullscreen mode

Top comments (0)