The El form item attribute prop in element

Recently, I was responsible for front-end and back-end project development. One requirement is to implement djangorest framework (drf) + element to dynamically render form forms. The drf back-end provides json, and the front-end obtains form elements from json and binds form validation rules
An error is reported on the property prop of El form item or it is not bound to data. The error is as follows
[Vue warn]: Error in render: "TypeError: Cannot read properties of undefined (reading 'prop')"
element the official document explains that the prop of El form item must be a direct sub attribute of El form attribute model
The data returned by the backend is as follows

{
    "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 name",
                "placeholder": "Please enter menu name",
                "rules": [
                    {
                        "required": true,
                        "message": "Please enter menu name",
                        "trigger": "blur"
                    }
                ]
            },
            {
                "type": "text",
                "prop": "path",
                "label": "Link address",
                "placeholder": "'/'start",
                "rules": [
                    {
                        "required": true,
                        "message": "'/'start",
                        "trigger": "blur"
                    }
                ]
            },
            {
                "type": "text",
                "prop": "component",
                "label": "assembly",
                "placeholder": "Refer to front end assembly",
                "rules": [
                    {
                        "required": true,
                        "message": "Refer to front end assembly",
                        "trigger": "blur"
                    }
                ]
            },
            {
                "type": "switch",
                "prop": "hidden",
                "label": "Hide",
                "value": false
            },
            {
                "type": "json",
                "prop": "meta",
                "item": [
                    {
                        "type": "text",
                        "prop": "icon",
                        "label": "Icon",
                        "placeholder": "Icon name, refer to the front Icon",
                        "rules": [
                            {
                                "required": true,
                                "message": "Icon name, refer to the front Icon",
                                "trigger": "blur"
                            }
                        ]
                    },
                    {
                        "type": "text",
                        "prop": "title",
                        "label": "title",
                        "placeholder": "Please enter menu name",
                        "rules": [
                            {
                                "required": true,
                                "message": "Please enter 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": "Authority management",
                        "value": 5
                    },
                    {
                        "label": "Role management",
                        "value": 6
                    }
                ]
            }
        ]
    },
    "message": null
}

As you can see from the above, the form element corresponds to the form_item_list, the form submission data is form_data, the two are separated, that is, the model binding in El form is form_data and El form item traverse the form_item_list, pay attention to form_ item_ The list contains nested type json, and the corresponding back end is the json field to render the form. The form is provided separately_ The data return field is designed to control the content of the front-end json. The dynamic fields are too flexible and the fields and types contained in the json can be modified at will. Therefore, the return fields are controlled and verified by the back-end

The code for intercepting the front-end rendering form is as follows. Note that it can be rendered at this time, but the rules binding fails

<!-- Add menu dialog box -->
    <el-dialog title="add menu" :visible.sync="addDialogVisible" width="50%" :close-on-click-modal="false" @close="addDialogClosed">

      <!-- Form content body -->
      <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>
            <!-- textarea Input box -->
            <el-input v-if="item.type==='textarea'" v-model="formData[item.prop]" clearable autosize :type="textarea" :placeholder="item.placeholder"></el-input>
            <!-- Drop down 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>
                  <!-- textarea Input box -->
                  <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 = false">cancel</el-button>
        <el-button type="primary" @click="addForm">determine</el-button>
      </span>
    </el-dialog>

The front-end rendering cannot be bound to form rules, as shown in the following figure

After research, it can be found from the above data structure that form_ Each element in data corresponds to a form_item_list, there are two ways to locate
The first way is as follows, which is not so intuitive

<!-- Normal field rendering -->
<el-form-item :prop="item.prop" :label="item.label" :rules="item.rules">
<!-- json Field rendering -->
<el-form-item :prop="item.prop + '.' + json_item.prop" :label="json_item.label" :rules="json_item.rules" style="margin-left: -80px;">

A better second way 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;">

At this time, you can dynamically render the form and bind the form item verification rules, as shown in the following figure

Summary: the above two methods are used to locate the direct sub attribute of the model of the form corresponding to the form element. The reason for stepping on the pit is that the traversal form list (v-for) and the form submission data (model) are not under the same object, especially the traversal form, but also include nested form json processing. You should pay attention to locating the json submission data

Keywords: Front-end Vue

Added by BK87 on Wed, 05 Jan 2022 03:04:54 +0200