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:
cssElementUI
:
1.1textarea
2.
debug:
1.el-form-itemprop
2.
3.
4.resetFields
5.resetFields
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.