On the failure of ElementUI form value type detection

just started contact with Vue and ElementUI, recently encountered problems in the development process and experienced all kinds of painful debug. Let"s get to the point:

it seems that you can"t transfer files here, so I"ll just paste the code:

<template>
    <div>
        <el-button @click="onSelect"></el-button>

        <el-dialog
        title=""
        :visible.sync="dialogVisible"
        width="50%">
            <el-form 
            ref="testForm" 
            :model="formData" 
            :rules="formRules">
                <el-form-item label="">
                    <el-select v-model="formData.class">
                        <el-option label="1" value="class1"></el-option>
                        <el-option label="2" value="class2"></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item label="class1" v-if="formData.class=="class1"" prop="text">
                    <el-input type="textarea" v-model="formData.text"></el-input>
                </el-form-item>
                <el-form-item label="2" v-else prop="value">
                    <el-select v-model="formData.value" multiple>
                        <el-option label="sdf" value="11"></el-option>
                        <el-option label="dsaf" value="22"></el-option>
                        <el-option label="dyrt" value="33"></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" @click="onSubmit">ok</el-button>
                </el-form-item>
            </el-form>
        </el-dialog>
    </div>
</template>

<script>
export default {
    data(){
        return {
            dialogVisible: false,
            formData: {
                class: "",
                text: "",
                value: []
            },
            formRules: {
                text: [{
                    required:true,
                    validator(rule, value, callback){
                        var Reg = /[\w+\/]*\w+/;
                        if(value==""){
                            callback(new Error(""))
                        }else if(!value.match(Reg) || value.match(Reg)!=value){
                            callback(new Error("/"));
                        }else{
                            callback();
                        }
                    }
                }],
                value: [{
                    required:true,
                    message:""
                }]
            }
        }
    },
    methods: {
        onSubmit(){},
        onSelect(){
            this.dialogVisible = true;
            this.$nextTick(() => {
                this.$refs.testForm.resetFields();
            });
            console.log(this.formData)
        }
    }
}
</script>

this component is a button, and a pop-up window appears when you click the button, as shown below:

clipboard.png

cssElementUI

:
1.1textarea
2.

debug:
1.el-form-itemprop
2.
3.
4.resetFields
5.resetFields

clipboard.png

clipboard.png

ask everyone to explain to me why the text value I defined is String, will become Array, after the form, whether I use non-standard or ElementUI itself thinks that the field value of textarea is Array or other problems, please correct. Here, I would like to thank all the bosses!


change v-if/v-else to v-show .

https://jsfiddle.net/s5ar1un3.

I just found out that there is such a pit. I will talk about it slowly behind the principle.

< H2 > the following is the element-ui source code < / H2 >

form.vue

//created
created() {
      this.$on('el.form.addField', (field) => {
        if (field) {
          this.fields.push(field);
        }
      }
      
      this.$on('el.form.removeField', (field) => {
        if (field.prop) {
          this.fields.splice(this.fields.indexOf(field), 1);
        }

      });
}

//
resetFields() {
        ...
        
        this.fields.forEach(field => {
          field.resetField();
        });
      },

form-item.vue

//mounted
    mounted() {
        if (this.prop) {
            this.dispatch('ElForm', 'el.form.addField', [this]);
            ...
            
            let initialValue = this.fieldValue;
            
            ...
            
            Object.defineProperty(this, 'initialValue', {
              value: initialValue
            });
            ...
        }
    }

//
    resetField() {

        this.validateDisabled = true;
        if (Array.isArray(value)) {
          prop.o[prop.k] = [].concat(this.initialValue);
        } else {
          prop.o[prop.k] = this.initialValue;
        }
    }

as you can see from the source code, the initial value of each field is determined in the mounted phase of form-item .

creation phase

because v-if/v-else , there is no prop when the component text is created (three item components are created, and class itself does not write prop ). Therefore, only the el.form.addField event of the form component is triggered when the item component of value is created. So the length of the saved fields is 1, and only value is saved.

selected
due to data changes, vue compares different updates, then updates the second component (this is the key) , but the goose this.initialValue is the value defined by element-ui or the original value value.

The result of

is that
resetField the value of value.initialValue is assigned to text .

< H2 > < del > conclusion < / del > < / H2 >

< del > so resetField never use v-if/v-show unless you have confirmed that the above logic does not conflict with your business logic. < / del >
< del > Test version element-ui@2.3.3 < / del >

< H2 > add < / H2 >

all of the above are the results of not looking at the document (fancy face punching). vue provides : key to prevent component reuse. ide/conditional.html" rel=" nofollow noreferrer "> Vuejs

Vue renders elements as efficiently as possible, usually reusing existing elements rather than rendering from scratch. In addition to making Vue very fast, this has some other benefits. For example, if you allow users to switch between different login methods

, this is not always in line with the actual needs, so Vue provides you with a way to express "these two elements are completely independent, do not reuse them." Just add a key attribute with a unique value:

Note that resetField is not reset , just as the validate component is not unvalidated.


if you don't follow your debug course, the problem has been solved a long time ago. If you don't have much to say, go to the code:

    <template>
    <div>
        <el-button @click="onSelect"></el-button>

        <el-dialog
                title=""
                :visible.sync="dialogVisible"
                width="50%">
            <el-form
                    ref="formData"
                    :model="formData"
                    :rules="formRules">
                <el-form-item label="">
                    <el-select v-model="formData.Type">
                        <el-option label="1" value="class1"></el-option>
                        <el-option label="2" value="class2"></el-option>
                    </el-select>
                </el-form-item>
                <div v-if="formData.Type=='class1'">
                    <el-form-item label="class1" prop="desc">
                        <el-input type="textarea" v-model="formData.desc"></el-input>
                    </el-form-item>
                </div>
                <div v-else>
                    <el-form-item label="2" prop="region">
                        <el-select v-model="formData.region" multiple>
                            <el-option label="sdf" value="11"></el-option>
                            <el-option label="dsaf" value="22"></el-option>
                            <el-option label="dyrt" value="33"></el-option>
                        </el-select>
                    </el-form-item>
                </div>
                <el-form-item>
                    <el-button type="primary" @click="onSubmit('formData')">ok</el-button>
                </el-form-item>
            </el-form>
        </el-dialog>
    </div>
</template>

<script>
    export default {
        data(){
            return {
                dialogVisible: false,
                formData: {
                    Type: 'class1',
                    desc: '',
                    region: []
                },
                formRules: {
                    desc: [
                        {
                            required:true,
                            validator(rule, value, callback){
                                var Reg = /[\w+\/]*\w+/;
                                if(value==''){
                                    callback(new Error(''))
                                }else if(!value.match(Reg) || value.match(Reg)!=value){
                                    callback(new Error('/'));
                                }else{
                                    callback();
                                }
                            }
                        }
                    ],
                    region: [
                        { required:true, message:'', trigger: 'change' }
                    ]
                }
            }
        },
        methods: {
            onSubmit(formName){
                this.$refs[formName].validate((valid) => {
                    if (valid) {
                        this.dialogVisible = false;
                        alert('submit!');
                    } else {
                        console.log('error submit!!');
                        return false;
                    }
                });
            },
            onSelect(){
                this.dialogVisible = true;
                this.$nextTick(() => {
                    this.$refs.formData.resetFields();
                    console.log(this.Type)
                });
                console.log(this.formData)
            }
        }
    }
</script>

your problem is v-if/v-else here, because your initial Type is'', VMI if = "formData.Type=='class1'", that's why you're showing textarea. But the second time you click, after you execute resetFields, Type is displayed as select for undefined, and the type of desc will change to be the same as region because of the reset, which explains why you choose type 2 for the first time and click in the second time and will not report an error.

Menu