How to use JavaScript strategy pattern to validate forms

How to use JavaScript strategy pattern to validate forms

Overview

In web projects, login, registration and other functions all require form submission. Before submitting the user's data to the backend, the frontend generally needs to do some verification within its capacity, such as whether the form is filled in, the length of the form, whether the password complies with the specifications, etc. Front-end verification can avoid submitting non-compliant forms.

Suppose we have a form with the following validation logic:

  • Username is not empty
  • Password length is not less than 6 characters
  • Mobile phone number conforms to the format

Form validation without using strategy pattern

When the strategy mode is not used, the first verification mode we think of is usually like this:

<body>
    <form id="registerForm">
        <label for="username">Enter username: <input type="text" name="username"></label>
        <label for="password">Enter password: <input type="password" name="password"></label>
        <label for="phone">Enter password: <input type="text" name="phone"></label>
    </form>
    <script>
        const form = document.querySelector('.registerForm');
        form.onsubmit = function(){
            if(form.username.value === ''){
                alert('Username cannot be empty')
                return;
            }
            if(form.password.value.length < 6){
                alert('Password length cannot be less than 6 characters')
                return;
            }
            if(!/(^1[3|5|8][0-9]{9}$)/.test(form.phone.value)){
                alert('The phone number format is incorrect')
                return;
            }
        }
    </script>
</body>

This way of writing code is very common, but its disadvantages are also obvious:

  • The onsubmit function is too large and contains many if-else statements to cover all rules.
  • The onsubmit function lacks flexibility. If you want to enter a new validation rule, you have to change the content of the function, which violates the open-closed principle.
  • The code reusability is poor. If you write another form, you have to copy a lot of duplicate code.

Optimize using the strategy pattern

First, encapsulate the verification function as an object:

const strategies = {
    empty(value, errMsg){
        if(value.length === 0){
            return errMsg;
        }
    },
    minLength(value, len, errMsg){
        if(value.length < len){
            return errMsg;
        }
    },
    isMobile(value, errMsg){
        if(!/(^1[3|5|8][0-9]{9}$)/.test(value)){
            return errMsg;
        }
    }
}

We also need a Validator class, which is used to add validation rules to the target form. Its usage is as follows:

const validate = function(){
    const validator = new Validator();
    validator.add(Form.userName, 'empty', 'Username cannot be empty');
    validator.add(Form.password, 'minLength:6', 'The password length cannot be less than 6 characters');
    validator.add(Form.phone, 'isMobile', 'The mobile phone number format is incorrect');
    const errMsg = validator.start();
    return errMsg;
}

As shown in the code, the validator instance has an add method that receives three parameters. The first one is the form instance that needs to be validated, the second one is the validation method, and the parameters after the colon are passed in. The third one is the error message if the verification fails.

The start method is used to start the verification. If it fails, a prompt message indicating that it has failed will be returned, which can be processed in the subsequent logic.

Writing of Validator class:

class Validator {
    constructor(){
        this.rules = [];
    }
    add(elem, rule, err){
        const args_arr = rule.split(":");
        this.rules.push(()=>{
            const handler = args_arr.shift();
            args_arr.unshift(elem.value);
            args_arr.push(err);
            return strategies[handler].apply(elem, args_arr)
        })
    }
    start(){
        let errmsg = []
        for(let i = 0; i < this.rules.length; i++ ){
            const err = this.rules[i]();
            if(err){
                errmsg.push(err)
            }
        }
        return errmsg.join(",");
    }
}

Using the strategy mode, we use the configuration method to complete the form verification. These rules can be used in any place where the form is verified in the future, which is more convenient for modification and reuse.

Add multiple validation rules to a single form field

Our code currently has a shortcoming, that is, it can only assign a single validation rule to a form item, and cannot implement multiple validation rules for a form, so there is room for improvement in the code.

class Validator{
    // ···
    add(elem, rules){
        rules.forEach(rule => {
            const args_arr = rule.strategy.split(":");
            this.rules.push(()=>{
                const handler = args_arr.shift();
                args_arr.unshift(elem.value);
                args_arr.push(rule.errMsg);
                return strategies[handler].apply(elem, args_arr)
            })
        });
    }
    // ···
}

const validate = function(){
    const validator = new Validator();
    validator.add(Form.username,[{
        strategy: 'empty',
        errMsg: 'Username cannot be empty'
    }]);
    validator.add(Form.password, [{
        strategy: 'minLength:6',
        errMsg: 'The password length cannot be less than 6 characters'
    }]);
    validator.add(Form.phone, [{
        strategy: 'isMobile',
        errMsg: 'The mobile phone number format is incorrect'
    }, {
        strategy: 'empty',
        errMsg: 'Phone number cannot be empty'
    }]);
    const errMsg = validator.start();
    return errMsg;
}

You only need to pass in an object array when passing parameters, and add the corresponding array processing logic in the add function.

Advantages of the Strategy Pattern

advantage:

  • Avoid multiple conditional select statements
  • Implementing the open-closed principle makes the use of functions easier to switch, easier to understand, and easier to expand.
  • Improve code reuse

Summarize

Peter Norvig said that in a language where functions are first-class objects, the strategy pattern is invisible, and strategy is a variable whose value is a function. In fact, it is the process of passing the encapsulated strategy function as a parameter to the target that uses it and being called by the target. Making good use of the strategy pattern not only allows us to have a deeper understanding of the pattern, but also makes us understand the benefits of using the function.

The above is the details of how to use JavaScript strategy mode to verify the form. For more information about JavaScript, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • How to implement the strategy pattern in Javascript
  • Detailed explanation of the use of JavaScript strategy mode from form validation
  • JavaScript design pattern strategy pattern implementation principle detailed explanation
  • JS form validation plug-in data and logic separation operation example analysis [strategy mode]
  • JavaScript Design Patterns – Strategy Pattern Principles and Usage Examples
  • Analysis of the concept and usage of strategy pattern in JS design pattern
  • JavaScript rewrites the asynchronous validation form into a synchronous form
  • Summary of three methods of submitting the form after js verifies the form
  • Easily master JavaScript strategy mode

<<:  How to configure mysql5.6 to support IPV6 connection in Linux environment

>>:  Detailed explanation of mysql permissions and indexes

Recommend

How to solve the problem of too many open files in Linux

The cause is that the process opens a number of f...

Experience of redesigning the homepage of TOM.COM

<br />Without any warning, I saw news on cnB...

Detailed explanation of Linux server status and performance related commands

Server Status Analysis View Linux server CPU deta...

Three methods of inheritance in JavaScript

inherit 1. What is inheritance Inheritance: First...

Summary of principles for writing HTML pages for emails

Since HTML email is not an independent HOST page o...

Summary of several common logs in MySQL

Preface: In the MySQL system, there are many diff...

HTML table markup tutorial (28): cell border color attribute BORDERCOLOR

To beautify the table, you can set different bord...

A brief analysis of the use of watchEffect in Vue3

Preface Everyone should be familiar with the watc...

Practice of using SuperMap in Vue

Table of contents Preface Related Materials Vue p...

Solve the problem of using less in Vue

1. Install less dependency: npm install less less...

MySQL slow query: Enable slow query

1. What is the use of slow query? It can record a...