Recently, I was responsible for the development of front and back end projects. I had a requirement to implement Djangorestframework(DRF)+element to dynamically render form forms. The DRF back end provides json, and the front end obtains form elements from json. [Vue warn]: Error in render: “TypeError: Cannot read properties of undefined (Reading ‘prop’)” Element The prop of an el-form-item must be a direct child of the el-Form attribute Model
{ "status": "success", "code": 200, "data": { "form_attributes": { "inline": true, "label-width": "auto", "size": "small" }, "form_data": { "name": null, "path": null, "component": null, "hidden": false, "meta": { "icon": null, "title": null }, "pid": null }, "form_item_list": [ { "type": "text", "prop": "name", "label": "Menu", "placeholder" : "please enter the menu name", "rules" : [{" required ": true," message ":" please enter the menu name ", "trigger" : "blur"}]}, {" type ": "Text", "prop" : "path", "label" : "links", "placeholder" : "'/' at the beginning", "rules" : [{" required ": true," message ": "'/' at the beginning," "trigger" : "blur"}}, {" type ":" text ", "prop" : "component", "label" : "components", "placeholder" : "Reference front-end components to fill in", "rules" : [{" required ": true," message ":" reference front-end components to fill in ", "trigger" : "blur"}]}, {" type ":" switch ", "prop" : "Hidden", "label" : "hide", "value" : false}, {" type ":" json ", "prop" : "meta", "item" : [{" type ":" text ", "prop" : "Placeholder ": "icon", "label": "icon", "placeholder": "icon name, refer to the front-end icon", "rules": [{"required": true, "message": "Icon name, reference the front-end icon", "trigger" : "blur"}}, {" type ":" text ", "prop" : "title", "label" : "title", "placeholder" : "Please enter the menu name", "rules" : [{" required ": true," message ":" please enter the menu name ", "trigger" : "blur"}]}}, {" type ":" select ", "prop" : "Pid ", "label":" parent menu ", "clearable": true, "filterable": false, "multiple": false, "options": [{"label": "System management", "value" : 2}, {" label ":" user management ", "value" : 3}, {" label ":" menu management ", "value" : 4}, {" label ":" rights management ", "value" : 5}, {" label ":" role management ", "value" : 6}]}}], "message" : null}Copy the code
Form_item_list, form_data, form_data, form_data, form_data So in el-form, the model binding is form_data and the el-form-item traverses form_item_list, and notice that form_ITEM_list contains nested json, and the corresponding back end is the JSON field rendering form, The form_data return field is designed to control the front-end JSON content. Dynamic fields are flexible, and the fields and types contained in THE JSON can be modified at will. Therefore, the return field is controlled and verified by the back-end
Intercepting the front-end rendering form code below, note that it can be rendered at this time but the rules binding fails
<! <el-dialog title=" Add menu ":visible. Sync ="addDialogVisible" width="50%" :close-on-click-modal="false" @close="addDialogClosed"> <! <el-form ref="addFormRef" :model="formData" :size="formAttributes. Size ":inline="formAttributes. Inline" :label-width="formAttributes.labelWidth"> <div v-for="(item, index) in formItemList" :key="index"> <el-form-item :prop="formItemList + index + item.prop" :label="item.label" :rules="item.rules"> <! -- text input box --> <el-input v-if="item.type==='text'" v-model="formData[item.prop]" clearable :placeholder="item.placeholder"></el-input> <! --> <el-input v-if="item.type==='textarea'" v-model="formData[item.prop]" clearable autosize :type="textarea" :placeholder="item.placeholder"></el-input> <! -- dropdown box --> <el-select v-if="item.type==='select'" v-model="formData[item.prop]" clearable :multiple="item.multiple"> <el-option v-for="op in item.options" :key="op.value" :label="op.label" :value="op.value"></el-option> </el-select> <el-switch v-if="item.type==='switch'" v-model="formData[item.prop]" :label="item.label"></el-switch> <template v-if="item.type==='json'"> <div v-for="(json_item, json_index) in item.item" :key="json_index"> <el-form-item :prop="item.item + json_index + json_item.prop" :label="json_item.label" :rules="json_item.rules" style="margin-left: -80px;" > <! -- text input box --> <el-input v-if="json_item.type==='text'" v-model="formData[item.prop][json_item.prop]" clearable :placeholder="json_item.placeholder"></el-input> <! --> <el-input v-if="json_item.type===' textaREA '" v-model="formData[json_item.prop]" clearable autosize :type="textarea" :placeholder="json_item.placeholder"></el-input> <! -- Drop down box --> <! -- <el-select v-if="item.type==='select'" v-model="formData[item.prop]" clearable :placeholder="item.label" :multiple="item.multiple" @change="item.change(formData[item.prop])"> --> <el-select v-if="json_item.type==='select'" v-model="formData[json_item.prop]" clearable :multiple="json_item.multiple"> <el-option v-for="op in json_item.options" :key="op.value" :label="op.label" :value="op.value"></el-option> </el-select> <el-switch v-if="json_item.type==='switch'" v-model="formData[json_item.prop]" :label="json_item.label"></el-switch> </el-form-item> </div> </template> </el-form-item> </div> </el-form> <! -- Bottom --> < el-Divider ></ el-Divider >< span slot="footer" class="dialog-footer"> <el-button @click="addDialogVisible = </el-button> </el-button type="primary" @click="addForm"> </el-button> </span> </el-dialog>Copy the code
Rendering on the front end cannot bind to form rules, as shown below
As we can see from the above data structure, each element in form_data corresponds to prop in form_item_list. So there are two ways to locate form_data. The first way is as follows
<! <el-form-item :prop="item.prop" :label="item.label" :rules="item.rules"> <! --> <el-form-item :prop="item.prop + '.' + json_item.prop" :label="json_item.label" :rules="json_item.rules" style="margin-left: -80px;" >Copy the code
A better second way to write it is as follows
<el-form-item :prop="formItemList[index].prop" :label="item.label" :rules="item.rules"> <el-form-item :prop="formItemList[index].prop + '.' + item.item[json_index].prop" :label="json_item.label" :rules="json_item.rules" style="margin-left: -80px;" >Copy the code
At this point, you can dynamically render the form and bind the form item validation rules, as shown below
Summary: The above two methods are used to locate the direct child attributes of the form’s model. The reason for the error is that the v-for for traversing the form and the form submission data (Model) are not in the same object, especially for traversing the form, and also include nested json processing, which requires attention to locate the JSON submission data