Application of Form in data stack: Verification

Posted by imawake on Wed, 12 Jan 2022 10:25:34 +0100

1, Introduction

The theme of this paper is the application of Form in the data stack, which aims to help you better understand the cognition and practice of Form verification and linkage verification through some examples that have been applied in the data stack and the small tips sorted out by the author.

This paper focuses on the verification of Form and its application in data stack, and prefers application summary and experience sharing. As we all know, we were born in the best era. Antd has helped us package most functions, namely open and use, and the API is detailed. However, even so, antd developers still optimize and explore again and again on the current basis. Therefore, the author hopes that this article can not only bring you business tips, I also hope to give you some ideas.

For other contents of Form, we will meet you in the application of Form in several stacks (Part 2).

2, What is a Form

I believe that you have been very proficient in the use of Form in daily development, but it is worth mentioning that you may have "what is the definition of Form? When will we choose to use Form?" This question is often not well answered.

definition:

  • Forms with data collection, verification and submission functions, including check boxes, radio boxes, input boxes, drop-down selection boxes and other elements;

Usage:

  • When we are used to create an entity or collect information, or need to verify the input data type, we can use the Form.

3, Form field verification (FormItem)

First, let's take a look at the two basic form field verification methods provided by antd

/* 
 *** 「Declarative form validation***
*/

<Form.Item
  {...formItemLayout}
  label="password"
  hasFeedback
  validateStatus={validateStatus}
  help={help}
>
    {getFieldDecorator('input', {
    })(<Input onChange={(e) => { this.handleClickOne(e)}} placeholder="Please enter a value"/>)
    }
</Form.Item>
/* 
 *** 「Custom form validation***
*/

<Form.Item
  {...formItemLayout}
  label="password"
  hasFeedback
>
    {getFieldDecorator('input_controlled', {
      validateTrigger: 'onBlur',
      rules: [{
          required: true,
          message: 'Please input a password!'
      }, {
          min: 5,
          message: 'Password length must be greater than 5 at least!'
      }, {
          validator: this.checkInputValue
      }]
  })(
      <Input placeholder="Please enter the bank card password" />
  )}
</Form.Item>

checkInputValue = (rule, value, callback) => {
    if (!value) return callback('Please input a password!')
    if (value.length <= 2) {
        callback('Length at least greater than 2')
    }
    if (value !== '222') {
        callback('Wrong password')
    }
    callback()
}

Please consider: what points can be optimized in the above custom verification?

Is it irregular to write callBack('string ') directly instead of callback (new Error ('ting') on the official website? In fact, it is not: in RC field form, it is clearly pointed out that the type of parameter error is actually sting. Of course, if it is written as new Error, it may look more elegant, but it is also right to write string directly;

Since a custom validator is defined in rules, can it be simplified to write only one? If the execution of multiple rules defined in rules fails, will one rule not be executed again? Will there be a problem of repetition of rules prompts?
First, the rules defined in rules will be executed one by one; Code simplification is also obvious, but it may be due to habit. The author has seen the business codes of some projects. In fact, the style is the same as that of the above codes. After transformation, the code is as follows:

<Form.Item
  {...formItemLayout}
  label="password"
  hasFeedback
  required
>
    {getFieldDecorator('input_controlled', {
      validateTrigger: 'onBlur',
      rules: [{
          validator: this.checkInputValue
      }]
  })(
      <Input placeholder="Please enter the bank card password" />
  )}
</Form.Item>

checkInputValue = (rule, value, callback) => {
    if (!value) return callback(new Error('Password cannot be empty!'))
    if (value.length <= 5) {
        return callback('Length at least greater than 2')
    }
    if (value !== '222') {
        return callback('Wrong password')
    }
    .........
    // Interface verification, etc
    callback()
}

It is not difficult to see that after the transformation, we can see the required verification rules at a glance, which is conducive to later troubleshooting. When there are too many rules, we won't go up and down to look back.

4, Form value verification (ValidateFields)

Having finished FormItem, now turn to ValidateFields, two example demo demonstrations

The following figure is an introduction to the usage of validataFields by antd. Please review it without repeating it

1. Verify all fields of the form value

This is frequently used in the data stack. Generally, when submitting the data of the form, verify all the current form fields first. The next operation can be carried out only after all the form fields pass the verification. (interface adjustment, linkage and other operations)

2. Verify the specified form field

For the correctness verification of the specified form field at a specific time point, if the specified form field passes the verification, the next operation can be carried out. The first parameter filename of validateFields will be used here. The array is the binding name of the specified form field.

form.validateFields(['xxx'],(err,values) => {
    if(err) return
  // Perform operations related to values
  ...
})

3. Add options verification and applicable scenarios of options in data stack

Verify the correctness of the field value during operation. You can add verification rules as required. API review is as follows:

Example scenario 1: (tag engine project)

Scenario Description: the first custom verification of the form fails and an error is reported. It is found that the account permissions are insufficient at the time of verification. At this time, we give the user the permissions they should have (the pop-up window is not closed). Click OK again and find that there is no effect.
Problem analysis: from the perspective of the use of antd, follow-up operations should not be continued when there is a field value error, but there is such a limit. The problem is that the user-defined verification result is generated, and the user-defined verification is time-effective. Therefore, at this time, we should make the self-defined verification accurate, use the options parameter and set the force to true, Before each "submit" (check value) operation, all check logic must be repeated. (refer to demo)

handleOk = () => {
this.props.form.validateFields({ force: true }, (err, values) => {
    if (err) return
    // this.props.handleOk(values)
});

};

4. Joint verification of multiple forms

Scenario Description: there are many similar situations in different businesses - there are multiple form forms in a page, so how should the verification of form forms be handled? (the following figure shows a historical function in label business, and the code is omitted temporarily)

Problem analysis: due to the historical reasons of the project, we put aside the design problems and discuss the verification scheme directly. First, there is the problem of multi-layer form nesting, that is, multiple form forms may be included or embedded in the same page. The core of similar problems is how to get the form instances of the current container and nested form examples in one page.

Solution: use the wrappedComponentRef portal provided by ref or RC form

/*
 * The core code idea is as follows
*/

class CustomizedForm extends React.Component { ... }
// use wrappedComponentRef
const CustomForm =  Form.create()(CustomizedForm);
<CustomForm wrappedComponentRef={(form) => this.form = form} />

At this time this.form namely CustomizedForm Examples of

The business code of the upper part (refer to the demo presented by the author) 🌟 Code details (link address: demo address)

class RowLevelConf extends React.Component<IProps, IState> {
  constructor(props) {
        super(props);
    }
    state: IState = {...}
    basicForm: any;
    levelForm: any;
        ... ...
         // Check logic 
    create = () => {
        const { form } = this.props;
        // Call the validate of the rule component itself
        this.levelForm.validateFields((err, values) => {
            if(err) return
            /** 
            *** ... Business processing logic
            **/ 
            form.validateFields(async (err, values) => {
                if (err) return
                /** 
                *** ... Business processing logic
                **/
            })
        })
    }
      ... ... 
  render() {
    ... ...
    return (
    ... ...
    <Form>
        <LevelInfo 
          isCreate={isCreate} 
          form={form} 
          ruleData={ruleData} 
          onRef={(formRef) => this.levelForm = formRef} 
        />

        <CommTitle 
          titleName='Associated user' 
          className='comm-title__margin' 
        />
        <BasicInfoForm 
          isCreate={isCreate} 
          ruleData={ruleData} 
          form={form} 
          onRef={(formRef) => this.basicForm = formRef} 
        />
    </Form>
     ... ... 
    )
  }  
}

Through our custom onRef method, you can pass ref in the self component layer

<Component
    ref={(ref) => { this.props.onRef(ref) }}
    ... other params ...
/>

Think: observe our verification code. Is there an optimization scheme?

// Check logic 
create = () => {
    const { form } = this.props;
    // Call the validate of the rule component itself
    this.levelForm.validateFields((err, values) => {
        if(err) return
        /** 
        *** ... Business processing logic
        **/ 
        form.validateFields(async (err, values) => {
            if (err) return
            /** 
            *** ... Business processing logic
            **/
        })
    })
}

Although the problem is solved, the verification of the form is indeed performed from top to bottom, but looking carefully at the code, there is actually a sequence, which means that the levelForm is verified first, and then the lower form is verified after success. How can they be verified at the same time to complete the optimization of the interaction between the code and verification?

Author's ideas tips: although validateFields Does not return promise,But there will be callback Method to put back errors and values,So we can give it a test promise Encapsulation.

5. Collision between table and form (component linkage verification)

Business scenario: in fact, there are various cases of form linkage in the data stack. Taking the data assets front project as an example, the author dynamically inserts a single piece of data into the table and realizes the customizable verification content:

The normal idea is to treat each item in the dataSource as a form or formItem. We extract it into a similar minimum structure. The reference address is "form in table"

Then analyze the verification method:

There may be two general ideas:

1. Use the new components attribute of antd table to customize the list element to override the default table element, and then use form in the user-defined list element;

2. Treat each row element of table as an independent form field (formItem), and then use form Validatefields for verification; (see demo demo for details)

The implementation methods of the two methods may be different, but in the final analysis, the verification core is the same. Here, the author decomposes them with idea 2:

const tableTitle = [
    {
        title: "ip address",
        dataIndex: "ip",
        key: "ip",
        width: 205,
        render: (ip, record, index) => (
            <Form.Item required>
                {getFieldDecorator(`mapping[${index}].ip`, {
                    initialValue: ip || "",
                    validateFirst: true,
                    validateTrigger: ["onChange", "onFocus"],
                    rules: [
                        {
                            validator: this.syslogIPValidator
                        }
                    ]
                })(
                    <Input
                        size="small"
                        style={{ width: "170px" }}
                        autoComplete="off"
                        placeholder={'placeholder'}
                    />
                )}
            </Form.Item>
        )
    },
]
... ...
this.props.form.validateFields((err, values) => {
    // to do sth
})

5, Thinking and summary

This article lists some antd form 3 Some typical applications of X in the data stack have combed some small tips and small demo s. I hope they can help you. So far, the verification method of form has been basically finished. Of course, if you have any supplement or questions, you are welcome to put forward them at any time.

For antd 4 For the form verification of X, a simple summary is also made here. Interested students can move to antd form 4 X explore:

First, there is a change to declarative verification:

<Form.Item
  {...formItemLayout}
  name="username"
  label="Name"
  rules={[
    {
      required: true,
      message: 'Please input your name',
    },
  ]}
>
  <Input placeholder="Please input your name" />
</Form.Item>

The second is "custom" verification. For custom verification, 4 The details of X have changed a lot. First look at the API:

Added warningOnly, isn't it great

The validator becomes promise. Is it the same as the above thinking?

mockSubmit = () => {
    form.validateFields().then((values)=>{
      // to do here 
    }).catch((errInfo)=>{  
      // If there is a form field that has not been verified, it will go to catch, which can print all verification failure information
      console.log('fail')
    console.log(errInfo)
    })
}

Topics: Front-end Big Data