Form validation

background

Suppose we are writing a registration page with the following verification logic when the registration button is clicked:

  • The user name cannot be empty
  • The password must contain at least six characters
  • The mobile phone number must conform to the format

Conventional writing:

const form = document.getElementById('registerForm');

form.onsubmit = function () {
  if (form.userName.value === ' ') {
    alert('User name cannot be empty');
    return false;
  }

  if (form.password.value.length < 6) {
    alert('Password length must not be less than 6 characters');
    return false;
  }

  if (!/ ^ 1 [3 | | 5 8] [0-9] {9} $/.test(form.phoneNumber.value)) {
    alert('Incorrect format of mobile number');
    return false; }... }Copy the code

This is a very common way of writing code, but it has many disadvantages:

  • onsubmitIt’s a big function, it contains a lot of thingsif-elseStatements that need to override all validation rules.
  • onsubmitFunctions are inelastic, so if we add a new validation rule, or want to change the password length from 6 to 8, we have to go deepobsubmitInternal implementation of a function, which is a violationOpen - close principle.
  • The algorithm is not reusable, and if we add another form to the project that requires some similar validation, we are likely to copy the validation logic all over the place.

How can you avoid these pitfalls and implement form validation more elegantly?

Introduction to Policy Mode

💡 Strategy pattern is a behavior design pattern that allows you to define a series of algorithms, encapsulate them one by one, and make them interchangeable.

Real world analogy

This figure comes fromRefactoringguru. Cn/design – patt…

If you need to get to the airport. You can choose to ride a bike, take a bus or take a taxi. These three travel strategies are “algorithms” in a broad sense, and they all get you from home to the airport. You don’t have to go into the internal implementation details of how to drive a bus or how the road system ensures access to the airport from your home. All you need to know about each of these strategies is how much time and money they will cost, and you can choose one of them based on factors such as budget and time.

A more generalized “algorithm”

In real development, we often diffuse the meaning of algorithms so that policy patterns can also be used to encapsulate a set of “business rules.” As long as these business rules point to consistent goals and can be used interchangeably, we can encapsulate them with policy patterns.

The composition of the policy pattern

A strategy pattern consists of at least two parts.

The first part is a set of policy classes, which encapsulate the specific algorithm and are responsible for the specific calculation process.

The second part is the Context class, which accepts a client’s request and then delegates it to a policy class.

Use strategy patterns for rewriting

Define rules (policies) that encapsulate form validation logic:

const strategies = {
  isNonEmpty: function (value, errMsg) {
    if (value === ' ') {
      returnerrMsg; }},minLenth: function (value, length, errMsg) {
    if (value.length < length) {
      returnerrMsg; }},isMobile: function (value, errMsg) {
    if (!/ ^ 1 [3 | | 5 8] [0-9] {9} $/.test(value)) {
      returnerrMsg; }}}Copy the code

Define the Context class, perform form validation, and call the policy:

form.onsubmit = function () {
	const validator = new Validator();
	validator.add(form.userName, 'isNonEmpty'.'User name cannot be empty');
	validator.add(form.password, 'minLength:6'.'Password length must not be less than 6 characters');
	validator.add(form.phoneNumber, 'isMobile'.'Incorrect format of mobile number');
	const errMsg = validator.start();
	if (errMsg) {
		alert(errMsg);
		return false; }}Copy the code

The Validator class code looks like this:

class Validator {
	constructor() {
		this.cache = [];
	}

	add(dom, rule, errMsg) {
		const arr = rule.split(':');
		this.cache.push(() = > {
			const strategy = arr.shift();
			arr.unshift(dom.value);
			arr.push(errMsg);
			returnstrategies[strategy].apply(dom, arr); })}start() {
		for (let i = 0; i < this.cache.length; i++) {
			const msg = this.cache[i]();
			if (msg) returnmsg; }}}Copy the code

After refactoring the code using the policy pattern, we eliminated a large number of conditional branch statements from the original program. Validation of a form can be done simply by “configuring” it, and these validation rules can be reused anywhere in the application and easily ported to other projects as plug-ins.

Advantages and disadvantages of strategic pattern

Advantages:

  1. Multiple conditional selection statements can be effectively avoided.
  2. rightOpen - close principlePerfect support, encapsulation of algorithms in a separate strategy, making them easy to switch, easy to understand, and easy to extend.
  3. The algorithm can be reused elsewhere in the system, avoiding a lot of repetitive copy-and-paste work.

Disadvantages:

  1. Using policy patterns adds many policy classes or policy objects to your program
  2. To use the strategy pattern, we must understand all strategies and understand their differences before we can choose an appropriate strategy. It’s against theLeast knowledge principle.

The policy mode is suitable for application scenarios

Policy patterns allow you to indirectly change the behavior of objects at run time by associating objects with different child objects that can perform specific subtasks in different ways.

The policy pattern allows you to extract different behaviors into a separate class hierarchy and combine the original classes into the same, thereby reducing duplicate code.

The policy pattern lets you isolate the code, internal data, and dependencies of various algorithms from other code. Algorithms can be executed by different clients through a simple interface and switched at run time.

The policy pattern extracts all algorithms that inherit from the same interface into separate classes, eliminating the need for conditional statements. The original object does not implement all variations of the algorithm, but delegates execution to one of the separate algorithm objects.

conclusion

In the example above, using the policy pattern has resulted in many more policy objects in the program and the code that executes the policy. However, this code can be reused anywhere in the application form, making the entire program code greatly reduced, and easy to maintain. Next time you need to check multiple forms, don’t write a bunch of if-else logic. Try policy mode!

Reference data

  • Delve into design patterns — strategic patterns
  • “JavaScript Design Patterns and Development Practices” — Zeng