background

When we are doing background management systems, we often encounter very complex forms:

  • There are many form items
  • Display different form items under various form types
  • Under certain conditions, some form items turn validation off
  • Each form item also has other custom logic, such as input fields that can insert template variables, display the number of input characters, upload and display images, rich text…
  • Complete the form validation and submission in this complex situation
  • Take a look at the examples: Many trivial features are omitted in this example, leaving the overall complex form framework to demonstrate the solution

Option 1: In avueIn the file

All the form item display and hide, validation, data retrieval, submission, customization, and so on are put together

  • Based on the form type, usev-if/v-showHandle form item display hiding
  • inelementuiIn custom authentication, you can determine whether a form item is authenticated according to the form type
  • Depending on the form type, different data is retrieved and submitted to different interfaces
  • All the rest of the custom logic

disadvantages

  • The disorderly
  • The disorderly
  • Or disorderly
  • avueFile, easily2000line
  • When I tried to add a new form type, I found that I had no more. From. Under. Hand.

Plan 2: Separate components

It’s easy to think of separate subforms based on different form types. However, I still encountered a lot of problems in practice: parent-child form validation, overall submission data acquisition, etc., and concluded a solution:

1. The child component

All child components need to contain two methods, validate and getData, for the parent component to call.

(1) validatemethods

A form item that validates its own component and returns a Promise object

vaildate() {
    // Returns the result of the 'elementUI' form validation (as a 'promise' object)
    return this.$refs["ruleForm"].validate();
},
    
Copy the code

(2) getDatamethods

Provides data in child components

getData() {
    // Returns the form of the child component
    return this.ruleForm;
},
Copy the code

2. The parent component

(1) The strategy pattern

Use the policy pattern to store and get the refs (the methods used to get the subforms) and submit functions for the subforms. A lot of if-else judgments are omitted.

data:{
  // A mapping between type and ref names
  typeRefMap: {
      1: "message".2: "mail".3: "apppush"
  },
  // The mapping between type and the submission function. Different types may have different interfaces
  typeSubmitMap: {
      1: data= > alert('The SMS template is created successfullyThe ${JSON.stringify(data)}`),
      2: data= > alert('The mail template was created successfullyThe ${JSON.stringify(data)}`),
      3: data= > alert(The 'push template is successfully createdThe ${JSON.stringify(data)}`)}},Copy the code

(2) submitmethods

Use for parent-child component form validation, get the whole data, and call the current type submit function to submit the data

Because the validate method of elementUI form validation can return a promise result, you can leverage the promise feature to handle parent-child form validation.

For example, then can return another promise object, and catch can take all of its then’s reject, promise.all.

  • The child forms are validated only if the parent form is validated. There is a precedence order
    // The child forms are validated only if the parent form is validated
    submitForm() {
        const templateType = this.typeRefMap[this.indexForm.type];
        this.$refs["indexForm"]
        .validate()
        .then(res= > {
            // After the parent form validates successfully, the child form is validated
            return this.$refs[templateType].vaildate();
        })
        .then(res= > {
            // All validation passes
            // Get the overall data
            const reqData = {
                // Get the child component data
                ...this.$refs[templateType].getData(),
                ...this.indexForm
            };
            // Get the submit function for the current form type and submit
            this.typeSubmitMap[this.indexForm.type](reqData);
        })
        .catch(err= > {
            console.log(err);
        });
    },
    Copy the code
  • Parent forms and child forms are validated together
    submitForm1() {
      const templateType = this.typeRefMap[this.indexForm.type];
      const validate1 = this.$refs["indexForm"].validate();
      const validate2 = this.$refs[templateType].vaildate();
      // Parent forms are validated together
      Promise.all([validate1, validate2])
        .then(res= > {
          // When both pass, send the request
          constreqData = { ... this.$refs[templateType].getData(), ... this.indexForm };this.typeSubmitMap[this.indexForm.type](reqData);
        })
        .catch(err= > {
          console.log(err);
        });
    },
    Copy the code

To viewOnline program,Project makingandComponent code

Conclusion: I have encountered this kind of complex form in many projects, and have used many solutions. I have concluded a relatively clean and simple solution here. Of course, there are many other scenarios, such as placing data submission methods in each child component, and passing common form item data to the child component via props for submission. There are other more concise solutions, please feel free to comment or make an issue on Github


Off topic: After reading the front End Architect’s personal narrative: The Road to growth of front End Engineer N q & A few answers, I have a lot of inspiration. In their own technical direction, confused prospects, or complain about their own project is too low, or complain about their repeated work every day, or every day to the endless new technology floundering, might as well take a serious look at their own projects,

  • Is it possible to build your own wheel if you repeat the work every day?
  • If the technology stack is too low, can it be smoothly transferred to the new technology to improve the development efficiency?
  • No matter how much new technology you learn, you will eventually come back and put it into practice.

By starting with the pain points of the workflow and project, you will progress more quickly in practicing, summarizing, and solving actual problems.


The feeling of writing this article: the difficulty of expressing these things >> the technical difficulty contained in the article itself

Lazy person improvement series:

How to improve development efficiency in the face of repetitive code and logic

Use class names for efficient flex layout

The Element-UI popover component encapsulates a minimalist solution

Simple use of business constants: Eliminate nasty find and mana values