Tree jam hope to bring you the fun of the front end of this article has been included github.com/littleTreem… Like to star ✨

Preface: I have been engaged in the middle and background project of to B direction these days, and I will contact with forms more frequently. I will talk about some basic sharing related to form data on a whim

1. Data processing

When the data displayed by the form in the view is not required by the back end, or the data returned by the back end is not displayed by the front end, data transformation is required. The following are some common scenarios

I assume that I have the following set of form base data

Data (){return {form:{name: 'trade ', nickName:' trade ', num: 'trade ', price:' trade ', tag:' trade ', nickName: 'trade ', num:' trade ', price:' trade ', tag: '0' // 1 means special price 0 means no special price},}},Copy the code

1.1 Scenario 1: Filtering my unwanted data

Scenario: The data in the current form has redundant fields, that is, the backend does not need these fields, we can filter out unnecessary fields

const noRequired = ['tag', 'nickName']; // Const formData = object.keys (this.form).filter(each =>! noRequired.includes(each)) .reduce((acc, key) => (acc[key] = this.form[key], acc), {});Copy the code

1.2 Scenario 2: Extract only the data I want

Scenario: This can be used when the backend does not require as much data as the form data, but only a portion of it

const formData= JSON.parse(
      JSON.stringify(this.form,["nickName","price"])
);
Copy the code

1.3 Scenario 3: Overwriting Data

Scenario: Available when some fields in the current form need to be replaced or new data needs to be overwritten

Object.assign(this.form, {tag: 'item 1'}Copy the code

1.4 Scenario 4: Field Mapping

If the current form fields need to be mapped to other field names, change the key value of name to name

  • Single field mapping
const formData = JSON.parse(
      JSON.stringify(this.form).replace(
        /name/g,
        'Name')
);
Copy the code

  • Multi-field mapping
const mapObj = {
      name: "Name",
      nickName: "NickName",
      tag: "Tag"
    };

const formData = JSON.parse(
      JSON.stringify(this.form).replace(
        /name|nickName|tag/gi,
        matched => mapObj[matched])
   );
Copy the code

Ps: There’s a bug with this approach. Do you know what it is?

1.5 Scenario 5: Data Mapping

It can be used when the state number of the field exists, such as 0, 1, needs to be converted into the corresponding representation. The corresponding tag field is as follows, 0 corresponds to special price, 1 corresponds to no special price, and the mapping conversion is carried out

Const formData = json.parse (json.stringify (this.form,(key,value)=>{if(key == 'tag'){return [' specials ',' specials '][value]; } return value; }));Copy the code

1.6 Scenario 6: Data Merge

Data merge, combining form data fields. Note that if the fields are the same, the values of the previous form data fields will be overwritten

Const query = {tenaId: 'order id ', id:' query ID'} const formData = {... this.form, query }Copy the code

2. Form verification

When the form data is filled in, it needs to do further form submission and transmission to the back-end server, but the front end needs to do further data compliance rules, such as whether it is mandatory, whether it is a mobile phone number format

2.1 Simple version of the single field check

data() { return { schema:{ phone: { required:true }, } }; Validate (schema, values) {for(field in schema) {if(schema[field].required) {if(! values[field]) { return false; } } } return true; }, } console.log(this.validate(schema, {phone:'159195**34'}));Copy the code

2.2 Simple version of multi-field checking

data() { return { phoneForm: { phoneNumber: '', verificationCode: '', tips:'' }, schema:{ phoneNumber: [{required: True, the error: 'mobile phones can't be empty'}, {regex: / ^ 1 [3 4 5 6 7 | | | | | 8] [0-9] {9} $/, error: 'cell phone format is wrong,}], verificationCode: [{required: True, error: 'Verification code cannot be empty '}],}}; }, methods: {const valArr = schema; for (const field in schema) { if (Object.prototype.hasOwnProperty.call(schema, field)) { for (const key of schema[field]) { if (key.required) { if (! valArr[field]) { valArr.tips = key.error; return false; } } else if (key.regex) { if (! new RegExp(key.regex).test(valArr[field])) { valArr.tips = key.error; return false; } } } } } return true; }, } console.log(this.validate(this.schema, this.phoneForm);Copy the code

2.3 Iview component library form component verification implementation

The Form component module of Iview is mainly composed of Form and FormItem

  • A Form encapsulates a Form
  • FormItem is a package that wraps form controls, prompts, validation rules, and so on.

Source link

We can clearly see that the iView form component uses the Async-Validator library as a form validation method

  • Basic use of async-Validator

The official example is the 👇 documentation link

import schema from 'async-validator';
var descriptor = {
  address: {
    type: "object", required: true,
    fields: {
      street: {type: "string", required: true},
      city: {type: "string", required: true},
      zip: {type: "string", required: true, len: 8, message: "invalid zip"}
    }
  },
  name: {type: "string", required: true}
}
var validator = new schema(descriptor);
validator.validate({ address: {} }, (errors, fields) => {
  // errors for address.street, address.city, address.zip
});
Copy the code

In the form component of iView, field. Validate is used to call the async-validator method to manage the validation under the form-item component

// ViewUI/src/components/form/form.vue methods:{ validate(callback) { return new Promise(resolve => { let valid = true; let count = 0; this.fields.forEach(field => { field.validate('', errors => { if (errors) { valid = false; } if (++count === this.fields.length) {// All finish resolve(valid); if (typeof callback === 'function') { callback(valid); }}}); }); }); }, // For a single validateField(prop, cb) {const field = this.field.filter (field => field.prop === prop)[0]; if (! field) {throw new Error('[iView warn]: must call validateField with valid prop string! '); } field.validate('', cb); } // resetFields() {this.fields.foreach (field => {field.resetfield (); }); },}, created () {// Use FormItem prop to collect checkable fields,  this.$on('on-form-item-add', (field) => { if (field) this.fields.push(field); return false; }); $on('on-form-item-remove', (field) => {if (field.prop) this.fields.splice(this.fields.indexof (field), 1); return false; }); }Copy the code

The rules in this.fields referred to in form. vue come in during its create life cycle by listening for ‘on-form-item-add’ push, The ‘on-form-item-add’ event is triggered by the form-item component, and the corresponding instance is passed to create the data association. The following is the content of the form-item lifecycle function:

/ / ViewUI/SRC/components/form/form - item. Vue mounted () {/ / if defines the fields need to verify the if (this. Prop) {/ / form component to add field to the father this.dispatch('iForm', 'on-form-item-add', this); Object.defineProperty(this, 'initialValue', { value: this.fieldValue }); this.setRules(); }}, beforeDestroy () {// Delete data field this.dispatch('iForm', 'on-form-item-remove', this) before removing; } methods: {setRules() {let rules = this.getrules (); if (rules.length&&this.required) { return; }else if (rules.length) { rules.every((rule) => { this.isRequired = rule.required; }); }else if (this.required){ this.isRequired = this.required; } this.$off('on-form-blur', this.onFieldBlur); this.$off('on-form-change', this.onFieldChange); this.$on('on-form-blur', this.onFieldBlur); this.$on('on-form-change', this.onFieldChange); }, getRules () { let formRules = this.form.rules; const selfRules = this.rules; formRules = formRules ? formRules[this.prop] : []; return [].concat(selfRules || formRules || []); }, validate(trigger, callback = function () {}) { let rules = this.getFilteredRule(trigger); if (! rules || rules.length === 0) { if (! this.required) { callback(); return true; }else { rules = [{required: true}]; }} // Set the AsyncValidator parameter this.validateState = 'validating'; let descriptor = {}; descriptor[this.prop] = rules; const validator = new AsyncValidator(descriptor); let model = {}; model[this.prop] = this.fieldValue; validator.validate(model, { firstFields: true }, errors => { this.validateState = ! errors ? 'success' : 'error'; this.validateMessage = errors ? errors[0].message : ''; callback(this.validateMessage); }); this.validateDisabled = false; }},Copy the code

Interested partners can on this basis through the study of the source code in-depth study of iView component library form verification of the concrete implementation.

2.4 Element component library ElForm form component verification implementation

Element’s ElForm component verification principle is very similar to the iView component library mentioned in the previous section. Here, I will not make a large description, directly “on the talent” —– source link

2.5 Common Verification Rules

Different regular rules are used to restrict whether different types of form data meet the requirements

  • Mobile phone number:/ ^ 1 [3 4 5 6 7 | | | | | 8] [0-9] {9} $/
  • Whether all numbers are:/ ^ [0-9] + $/
  • Email address:/ ^ ([A Za - z0-9 _ \ - \]) + \ @ ([A - Za - z0-9 _ \ - \]) + \. ([A Za - z] {2, 4}) $/
  • Id card or not:/^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d {4})|\d{3}[Xx])$)$/
  • Url or not:/ [- a - zA - Z0-9 @ : %. _ \ + ~ # =] {2256} \. [a-z] {2, 6} \ b ([9 - a - zA - Z0 - @ : % _ \ +. ~ #? & / / =] *) /
  • IP address or not:/((2(5[0-5]|[0-4]\d))|[0-1]? (\ \ d {1, 2}). ((2 (5 [0 to 5] | \ [0-4] d)) | [0, 1]? \ d {1, 2} {3})) /