Form verification is the most common part of form development. It allows us to customize the verification rules. When the information entered by the user does not conform to the verification rules, it can throw a prompt to guide the user to fill in the information that conforms to the verification rules. However, if form validation is poorly handled, such as inconsistent or incorrect prompts, it can lead to a poor user experience and even mislead users and hinder the form submission process. This article will take the FormModel of VUe2 ANTD framework as an example to list several situations that are prone to bugs in development and affect the experience.

If a-form-model-item has multiple child elements, the blur/change event of the form element cannot be monitored in real time.

In development, sometimes an A-form-model-item has more than one child element. For example, the following code contains two spans and an A-input tag:

<template> <a-form-model ref="ruleForm" :model="form" :rules="rules"> < A-form-model-item label=" prop="number"> <span style="margin-right: 5px"> </span style="display: inline-block; width: 200px; margin-right: 5px" type="number" V-model ="form.number" placeholder=" fill in number" ></a-input> <span> <a-form-model-item> < A-button@click ="onSubmit"> </a-button> </a-form-model-item> </a-form-model> </template> <script> Export default {data() {return {form: {name: ",}, rules: {number: [{required: true, message: 'Please fill in the number ', trigger: 'blur'}, ], }, }; }, methods: { onSubmit() { this.$refs.ruleForm.validate(valid => { if (valid) { alert('submit! '); } else { console.log('error submit!! '); return false; }}); ,}}}; </script>Copy the code

As a result, when the input field is empty, clicking the submit button triggers validation according to rules and displays the required input field prompt (as we expect). Fill in the input box and expect the prompt to disappear when the input box is out of focus, but it doesn’t. The prompt remains. Ignoring the prompt, we continued to click the submit button and found that the verification passed and the form was submitted successfully. The prompt disappeared. That is, when the input field is filled in, the form validation rules are actually met, but the prompt does not disappear in time (which is not what we expect). The renderings are as follows:

When the user fills in the input field, the page still asks the user to fill in the input field, which can seriously mislead the user into thinking that they filled in the wrong field, or even that the page is buggy and unusable (which it is –). When I first discovered this problem, I was puzzled until I looked at the document

Form.Item hijacks unique child elements and listens for blur and change events for auto-validation purposes, so make sure there are no other elements wrapped in the Form field. If there are more than one child, only the first child will be listened for.

Now we know the reason for the above bug: a-input is not the first child of a-form-model-item. According to the documentation, we changed the A-form-model-item part of the code above to show and hide the hints correctly.

<! -- ++ a-form-model-item add ref attribute ++ --> <a-form-model-item ref="number" label=" warning interval "prop="number"> <span Word-wrap: break-word! Important; "> < span style="margin-right: 5px"> <a-input style="display: inline-block; width: 200px; Margin-right: 3px "type="number" v-model="form.number" placeholder=" @blur=" () => {$refs.number.onfieldblur (); - input} "> < / a > < span > minutes remind a < / span > < / a - form - model - item >Copy the code

The effect is as follows:

Second, the values of multiple form elements are combined to determine whether the verification is passed

Let me give you an example just to make it easier to understand. For example, consider a scenario where there are multiple pull-down selectors that can be selected. Each pull-down selector is not required to have a selection, but at least one of them is required. We can write this:

<template> <a-form-model ref="ruleForm" :model="form" :rules="rules"> <a-form-model-item prop="select"> <a-form-model-item label=" selector 1"> < A-select mode="multiple" style="width: 300px" v-model="form.result1" > <a-select-option v-for="i in 25" :key="(i + 9).toString(36) + i" > {{ (i + 9). ToString (36) + I}} </a-select-option> </a-select> </a-form-model-item> < A-form-model-item label=" selector 2"> < A-select mode="multiple" style="width: 300px" v-model="form.result2" > <a-select-option v-for="i in 25" :key="(i + 9).toString(36) + i" > {{ (i + 9).toString(36) + i }} </a-select-option> </a-select> </a-form-model-item> </a-form-model-item> <a-form-model-item> <a-button type="primary" @click="onSubmit"> </a-button> </a-form-model> </a-form-model> </template> <script> export default { data() { const checkSelect = (rule, value, callback) => { if (this.form.result1.length + this.form.result2.length > 0) { callback(); } else {callback(new Error(" select at least one item ")); }}; return { form: { result1: [], result2: [], }, rules: { select: [ { validator: checkSelect, trigger: "change", }, ], }, }; }, methods: { onSubmit() { this.$refs.ruleForm.validate((valid) => { if (valid) { alert("submit!" ); } else { console.log("error submit!!" ); return false; }}); ,}}}; </script>Copy the code

In the above code, an A-form-model-item wraps two A-form-model-items containing select, and adds the prop attribute to configure the corresponding rules checksum. This creates a similar problem with the first case: the checkmark will appear and disappear correctly only when the button is clicked, and the change event will not update the checkmark. The effect is as follows:

I went back to the documentation and found that the prop for custom validation is only for a single form element, so it looks like we need to solve the problem ourselves. My idea was to leave the validation work that prop couldn’t handle to ourselves, with the goal of showing or hiding prompts correctly when clicking on the submit button or when a form element triggers a blur or change event. First, we write a component that mimics the official error message, and then dynamically determine when the error message component appears. The hint component is just a visual hint. The real verification interception logic needs to be implemented in the submit form event. Because the judgment condition of whether to hide the prompt component and whether the form control used by the prompt component passes the verification is the same, we can judge whether this part of the form control passes the verification by whether the prompt component is displayed or not. The code and renderings are as follows:

<! <template> <div class="hint-container"> <slot></slot> <transition name="drop-transform" mode=" out-of-in "> <div v-show="show" class="text">{{ hint }}</div> </transition> </div> </template> <script> export default { name: "Hint", props: { show: { type: Boolean, default: false, }, hint: { type: String, required: true, }, }, }; </script> <style scoped> .hint-container { position: relative; padding-bottom: 24px; } .text { position: absolute; left: 0; bottom: 24px; color: #f5222f; }.drop-enter-active,.drop-leave-active {transition: opacity 0.28s; } .drop-enter, .drop-leave-active { opacity: 0; } /* drop-transform */. Drop -transform-leave-active,. Drop -transform-enter-active {transition: all 0.5s; } .drop-transform-enter { opacity: 0; transform: translateY(-10px); } .drop-transform-leave-to { opacity: 0; transform: translateY(-10px); } </style>Copy the code
<! -- form page --> <template> <a-form-model ref="ruleForm" :model="form" :rules="rules"> <a-form-model-item label=" name" prop="name"> <a-input style="width: 300px" V-model ="form.name"></a-input> </a-form-model-item> <hint :show="showHint" hint=" select at least one person ">< template #default> <a-form-model-item label=" "> <a-select mode="multiple" style="width: 300px" v-model="form.result1" > <a-select-option v-for="i in 25" :key="(i + 9).toString(36) + i" > {{ (i + 9). ToString (36) + I}} </a-select-option> </a-select> </a-form-model-item> < A-form-model-item label=" Internal staff "> < A-select mode="multiple" style="width: 300px" v-model="form.result2" > <a-select-option v-for="i in 25" :key="(i + 9).toString(36) + i" > {{ (i + 9).toString(36) + i }} </a-select-option> </a-select> </a-form-model-item> </template> </hint> <a-form-model-item> <a-button type="primary" @click="onSubmit"> </a-button> </a-form-model> </a-form-model> </template> <script> import Hint from ".. /components/Hint"; export default { components: { Hint, }, data() { return { form: { name: "", result1: [], result2: [], }, rules: { name: [{required: true, trigger: "change", message: "Please fill in your name ",},],},}; }, computed: { showHint() { return this.form.result1.length + this.form.result2.length === 0; }, }, methods: { handleFail() { console.log("error submit!!" ); return false; }, onSubmit() { this.$refs.ruleForm.validate((valid) => { if (valid) { if (this.showHint) { this.handleFail(); } else { alert("submit!" ); } } else { this.handleFail(); }}); ,}}}; </script>Copy the code

As you can see from the renderings, the Hint component achieves its goal of displaying verification information correctly, and the UI looks pretty much the same as the official one. However, it may have one flaw: the prompt appears when the form is first displayed, which is not the same logic as the official prompt. There are two points worth thinking about: 1. How to better let users know the rules of filling forms in complex form scenarios. With this in mind, it seems like a good idea to display the prompt at the beginning of the example above, rather than an asterisk for each selector’s label. 2. Is there a better form presentation method? In the example above, we construct the form with multiple selectors that can be selected, and ultimately expect the user to arbitrarily select at least one value. But we can actually use multiple trees instead, as shown below:



Is it better to use trees instead of multiple selectors? The answer is not necessarily. Sometimes, a single selector has hundreds or thousands of data sources, and it is not feasible to combine the massive data sources of several selectors into a tree, so the choice will be made on a case-by-case basis.

Third, hidden elements still trigger validation

Sometimes we dynamically display hidden form element Y based on the value of form element X. When y is displayed, we want to add validation to it. When y is hidden, no validation is required. In order to reduce the initial rendering overhead with v-show, write the following code:

<template> < A-form-model ref="ruleForm" :model="form" :rules="rules"> < A-form-model-item label=" Do I need reminding "> < A-radio-group V-model =" form.need.reminder "> < A-radio value="1"> Yes </ A-radio > < A-radio value="0"> No </ A-radio > </a-radio-group> </a-form-model-item> < A-form-model-item V-show ="form.needReminder === '1'" label=" reminder "prop="type" > < A-radio-group V-model ="form.type"> <a-radio value="1"> Mode 1</ A-radio > < A-radio value="2"> Mode 2</a-radio> </a-radio-group> </a-form-model-item> <a-form-model-item> <a-button type="primary" @click="onSubmit"> </a-form-model-item> </a-form-model> </template> <script> export default { data() { return { form: { needReminder: "0", type: "", }, rules: {type: [{required: true, message: "Please select the notification mode ", trigger: "change",},],},}; }, methods: { onSubmit() { this.$refs.ruleForm.validate((valid) => { if (valid) { alert("submit!" ); } else { console.log("error submit!!" ); return false; }}); ,}}}; </script>Copy the code

The problem with the code above is that when we choose not to be reminded, the hidden checkbox that selects the reminding mode still triggers validation, so an error is reported and the submission cannot be made. The effect is as follows:

The solution to this problem is simple, just replace v-show with V-if. However, if v-if is used to show and hide dynamically frequently, the DOM will be re-rendered multiple times. Fortunately, this doesn’t happen too often.

conclusion

The above describes several form verification scenarios, the title is to step on the pit, in fact, the pit is not the UI framework, but we need to treat carefully, otherwise we will dig holes. A tester once tested a form I had developed and said that the process would not run, kept reporting errors and could not be submitted. I am a leng, their debugging. In fact, the form that the tester said could not run could pass the verification, but the prompt information in the above example was not updated in time. After all, you ignore some incorrect form prompts, assuming that users will ignore them and click submit first. Since then, I’ve come to appreciate the importance of formverification specifications. After all, the goal of our development is to provide a better user experience, which is why I wrote this article.