With the update of the article and the growth of the code, in order to facilitate reading and practice, I published the code on Gitee from this article. The code address is as follows. If you want to see the end result, switch to the corresponding branch of this article; If you want to follow the article step by step, switch to the branch of the previous article and work on the article. (There was no branch in chapter 5, but it will be added later)

Code address: gitee.com/wyh-19/supe… This article is based on the following code: Essay-6

Series of articles:

  • Vue + Element Large Forms solution (1)– Overview
  • Vue + Element Large Forms solution (2)– Form splitting
  • Vue + Element Large Forms Solution (3)– Anchor Components (part 1)
  • Vue + Element Large Form Solution (4)– Anchor Component (2)
  • Vue + Element Large Forms solution (5)– Validation identifier
  • Vue + Element Large Forms solution (6)– Automatic identification
  • Vue + Element Large Forms solution (7)– Form form
  • Vue + Element Large Form Solution (8)– Data comparison (1)
  • Vue + Element Large Form Solution (9)– Data comparison (2)
  • Vue + Element Large Forms solution (10)– Form communication and dynamic forms

preface

The previous article implemented save-time validation of forms and identified failed subforms in anchor points. However, tags do not automatically mark the form as it is filled in, which can cause some confusion to users. This article will implement automatic identification of form status in the anchor point.

Implementation approach

Element’s form provides the validate event, which is triggered when any form item is validated to obtain the validation result of the table item. Take advantage of the ability provided by this event to notify the main form that the subform validation has failed when the validation result of any form item is false. When all form entries have passed, notify the main form that the subform has passed.

The implementation process

Add the validate event to the subform

Enter the form1.vue file and add the validate event to the el-form as follows:

<el-form ref="form" :model="formData" :rules="rules" @validate="handleValidate" label-width="80px" size="small">
Copy the code

The corresponding event handlers are as follows:

/ /!!!!!! Add ruleResults: {} to data. RuleResults: {
handleValidate(rule, isValid) {
  // Check whether all items pass
  this.ruleResults[rule] = isValid
  if(! isValid) {// Whenever this item fails, the main form is notified of a validation failure
    this.$emit('validate'.false)}else {
    let result = true
    // If there are any failed entries, this form fails to pass the verification
    for (const key in this.ruleResults) {
      if (!this.ruleResults[key]) {
        result = false
        break}}// Notify the main form that the validation has passed when there are no failed entries
    if (result) {
      this.$emit('validate'.true)}}}Copy the code

The ruleResults are cached with the ruleResults when any of the ruleResults are validated. The ruleResults are validated with true and the ruleResults are validated with false.

Back in the main form, add the validate event handler to the form1 component:

<form1 ref="form1" :data="formDataMap.form1" @validate="handleValidate('form1',$event)" />
Copy the code

The corresponding handler functions are as follows:

handleValidate(formKey, isValid) {
  // Find the section by formKey
  const section = this.pageBlock.querySelector(`[data-for=${formKey}] `)
  if(! isValid) { section? .setAttribute('data-tip'.' ')}else{ section? .removeAttribute('data-tip')}this.$refs['anchor'].reRender()
}
Copy the code

The logic is simple: find the section by the name of the subform, mark or remove the section based on the result passed by the subform, and update the anchor point. Test the effect. When the form item is verified, the status of anchor points on the right will be automatically updated, as shown below:

Draw a mixin

Since the validate event handler is also added to the subform form2, the code added in form1 is ported to the mixin as follows:

import { easyClone } from '@/utils'
export default {
  props: {
    data: {
      type: Object.default: () = >({})}},data() {
    return {
      formData: {},
      ruleResults: {}}}.watch: {
    data: {
      handler(newValue) {
        this.formData = easyClone(newValue) || {}
      },
      immediate: true}},methods: {
    validForm() {
      let result = false
      this.$refs['form'].validate((valid) = > { result = valid })
      return result
    },
    handleValidate(rule, isValid) {
      // Check whether all items pass
      this.ruleResults[rule] = isValid
      if(! isValid) {// Whenever this item fails, the main form is notified of a validation failure
        this.$emit('validate'.false)}else {
        let result = true
        // If there are any failed entries, this form fails to pass the verification
        for (const key in this.ruleResults) {
          if (!this.ruleResults[key]) {
            result = false
            break}}// Notify the main form that the validation has passed when there are no failed entries
        if (result) {
          this.$emit('validate'.true)}}}}}Copy the code

In form2.vue, just add @validate=”handleValidate” to the el-form and add @validate=”handleValidate(‘form2’,$event)” to the form2 component of the main form. You can add automatic identification capability to subform 2 as well. The effect is as follows:

With mixins, you can quickly give similar components the same capabilities, and later additions of new functionality or code changes will directly modify the mixin file.

Code optimization

To do this, the code needs to make the following optimizations:

  1. It has appeared several times in the main formthis.$refs['anchor'].reRender()The code needs to be optimized for local function calls so that it has better control over redrawing (for example, when the page does not need anchor components in certain states, the function body can make more detailed judgments), and add localreRenderAnchorFunction, code as follows:
reRenderAnchor() {
  if (this.$refs['anchor']) {
    this.$refs['anchor'].reRender()
  }
}
Copy the code

And modify this.$refs[‘anchor’].rerender () to this.rerenderAnchor ().

  1. When the validation rule for a form item is change, each input change triggers a subformel-formThe component’svalidateEvent that triggers the subform of the main formvalidateEvent, which ultimately translates into DOM manipulation and anchor redraw code execution, so use anti-shake to save performance. In mixin, the handleValidate function is modified as follows:
handleValidate: debounce(function(rule, isValid) {
  // Check whether all items pass
  this.ruleResults[rule] = isValid ... Code unchanged, omit},200)
Copy the code
  1. The use of subforms in the main form is now as follows:
<form1 ref="form1" :data="formDataMap.form1" @validate="handleValidate('form1',$event)" />.<form2 ref="form2" :data="formDataMap.form2" @validate="handleValidate('form2',$event)" />
Copy the code

Where ref uses the form key value, there is no optimization method for the moment, but the form key value is used many times in subsequent attributes or events. With the expansion of business, more formkeys may be written, such as:

<form1 ref="form1" :data="formDataMap.form1" :old-data="oldFormDataMap.form1" @validate="handleValidate('form1',$event)" />
Copy the code

This is not good for maintenance, so I want to specify the formKey only once, so I change the HTML to look like this:

<form1 ref="form1" form-key="form1" :data="formDataMap" @validate="handleValidate" />.<form2 ref="form2" form-key="form2" :data="formDataMap" @validate="handleValidate" />
Copy the code

This minimizes the number of times form1 and form2 are written and avoids errors that are hard to find. To support component parameter passing, we need to modify the mixin to props and add formKey as follows:

formKey: {
  type: String.default: ' '
},
Copy the code

Since the data passed in by the parent form is a complete formDataMap, it is necessary to disassemble the form data it needs according to the formKey in the sub-form, and add the calculation attribute of partFormData. The code is as follows:

computed: {
    partFormData() {
      return this.data[this.formKey]
    }
}
Copy the code

And localize the partFormData to formData as follows:

watch: {
    // data: {
    // handler(newValue) {
    // this.formData = easyClone(newValue) || {}
    / /},
    // immediate: true
    // },
    // The formData attribute was directly localized to formData
    partFormData: {
      handler(newValue) {
        this.formData = easyClone(newValue) || {}
      },
      immediate: true}}Copy the code

$emit(‘validate’, this.formKey, true/false); Through this series of modifications, the complete mixin code is as follows:

import debounce from 'lodash.debounce'
import { easyClone } from '@/utils'
export default {
  props: {
    formKey: {
      type: String.default: ' '
    },
    data: {
      type: Object.default: () = >({})}},data() {
    return {
      formData: {},
      ruleResults: {}}}.computed: {
    partFormData() {
      return this.data[this.formKey]
    }
  },
  watch: {
    partFormData: {
      handler(n) {
        this.formData = easyClone(n) || {}
      },
      immediate: true}},methods: {
    validForm() {
      let result = false
      this.$refs['form'].validate((valid) = > { result = valid })
      return result
    },
    handleValidate: debounce(function(rule, isValid) {
      // Check whether all items pass
      this.ruleResults[rule] = isValid
      if(! isValid) {// Whenever this item fails, the main form is notified of a validation failure
        this.$emit('validate'.this.formKey, false)}else {
        let result = true
        // If there are any failed entries, this form fails to pass the verification
        for (const key in this.ruleResults) {
          if (!this.ruleResults[key]) {
            result = false
            break}}// Notify the main form that the validation has passed when there are no failed entries
        if (result) {
          this.$emit('validate'.this.formKey, true)}}},200)}}Copy the code

When I finally tested it, it worked perfectly, and the code looked exactly as I wanted it to, setting the type for subsequent form passes. Thank you for reading, and your comments are welcome!