원클릭으로
el-plus-crud-form-group
Multi-section grouped form with independent validation per group, shared submit lifecycle, and dynamic group visibility
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Multi-section grouped form with independent validation per group, shared submit lifecycle, and dynamic group visibility
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | el-plus-crud-form-group |
| description | Multi-section grouped form with independent validation per group, shared submit lifecycle, and dynamic group visibility |
| version | 1.0.0 |
| origin | el-plus-crud |
| tags | ["vue3","element-plus","form-group","multi-section-form","grouped-form"] |
ElPlusFormGroup organizes multiple ElPlusForm instances into a grouped form. Each group has its own title, column count, and formDesc. Supports dynamic group visibility (vif), cross-group joint validation, and a unified submit lifecycle. Typical scenarios: multi-section detail pages, complex edit pages, wizard-style forms.
<ElPlusFormGroup> componentIFormGroupConfig configurationinterface IFormGroupConfig {
column?: number // Default column count for all groups
beforeValidate?: (data) => any // Pre-validation hook
beforeRequest?: (data) => any // Pre-submit hook
requestFn?: (data) => Promise // Submit function
updateFn?: (data) => Promise // Update function
success?: (formBack: IFormBack) => any // Success callback
successTip?: string | ((data?) => string)
tableRef?: any // Table ref for auto-reload after success
group: Array<{
title?: string // Group title (renders as left-border heading)
formDesc: IFormDesc // This group's form fields
column?: number // Override global column count
vif?: boolean | ((data?) => boolean) // Dynamic group visibility
fid?: string // Stable group identifier
showBtns?: boolean // Show submit buttons (auto: only last group)
maxWidth?: string
labelWidth?: string | number
}>
}
Each group creates an independent ElPlusForm instance. The FormGroup manages them through a formRefs array:
modelValue object — field names must not overlap across groupsgroupFormDesc collects all visible groups' formDesc for unified data processingExternal beforeValidate (IFormGroupConfig level)
→ Promise.all(formRefs.map(ref => ref.validate()))
All groups are validated in parallel. If any group fails, the entire submission is rejected.
getData() merges all groups' form data into a single object:
function getData() {
const tempData = {}
formRefs.value.map(tempRef => Object.assign(tempData, tempRef.getData()))
return tempData
}
group: [
{ title: '基本信息', formDesc: basicDesc },
{ title: '企业信息', formDesc: companyDesc, vif: (data) => !!data.isCompany },
{ title: '附加信息', formDesc: extraDesc }
]
When vif returns false, the group is filtered out and its fields are excluded from validation and data collection.
Slots are indexed by group position:
<ElPlusFormGroup v-model="formData" :formGroup="formGroupConfig">
<template #title0><h3>Custom Title for Group 0</h3></template>
<template #default1><div>Extra content in Group 1</div></template>
<template #top2><div>Content above Group 2</div></template>
</ElPlusFormGroup>
Available slot names: top{index}, title{index}, default{index} for each group.
const groupRef = ref()
await groupRef.value.validate() // Validate all groups (parallel)
groupRef.value.getData() // Get merged form data
groupRef.value.clearValid() // Clear validation for all groups
groupRef.value.clear() // Clear data for all groups
groupRef.value.init() // Init all group components
<ElPlusFormGroup v-model="formData" :formGroup="formGroupConfig" />
const formData = ref({})
const formGroupConfig: IFormGroupConfig = {
column: 2,
requestFn: api.saveProfile,
success: ({ callBack }) => {
ElMessage.success('保存成功')
callBack()
},
group: [
{
title: '基本信息',
formDesc: {
name: { type: 'input', label: '姓名', required: true },
phone: { type: 'input', label: '手机号', rules: 'phone' },
email: { type: 'input', label: '邮箱', rules: 'email' }
}
},
{
title: '地址信息',
formDesc: {
province: { type: 'area', label: '地区', required: true },
address: { type: 'input', label: '详细地址' }
}
},
{
title: '备注',
formDesc: {
remark: { type: 'textarea', label: '备注信息', colspan: 2 }
}
}
]
}
const formGroupConfig: IFormGroupConfig = {
column: 2,
requestFn: api.save,
group: [
{ title: '个人信息', formDesc: personalDesc },
{
title: '企业信息',
formDesc: companyDesc,
column: 3,
vif: (data) => data.userType === 'company'
},
{ title: '其他', formDesc: otherDesc }
]
}
<ElPlusFormGroup v-model="formData" :formGroup="formGroupConfig">
<template #title0>
<div style="color: #409eff; font-size: 18px; font-weight: bold;">
基本信息
</div>
</template>
<template #default1>
<el-divider />
</template>
</ElPlusFormGroup>
const groupRef = ref()
const handleSubmit = async () => {
try {
await groupRef.value.validate()
const data = groupRef.value.getData()
await api.save(data)
ElMessage.success('保存成功')
} catch (e) {
console.error('验证失败', e)
}
}
const handleReset = () => {
groupRef.value.clear()
}
<!-- FAIL: Don't manually manage multiple forms -->
<div class="section"><h3>基本信息</h3><ElPlusForm ref="form1" :formDesc="desc1" /></div>
<div class="section"><h3>地址</h3><ElPlusForm ref="form2" :formDesc="desc2" /></div>
const submit = async () => {
await form1.value.validate()
await form2.value.validate()
const data = { ...form1.value.getData(), ...form2.value.getData() }
await api.save(data)
}
<ElPlusFormGroup v-model="formData" :formGroup="formGroupConfig" />
// FAIL: IFormGroupConfig has ONE shared requestFn, not per-group
group: [
{ title: 'A', formDesc: descA, requestFn: api.saveA },
{ title: 'B', formDesc: descB, requestFn: api.saveB }
]
const formGroupConfig: IFormGroupConfig = {
requestFn: (data) => api.saveAll(data),
beforeRequest: (data) => {
// Handle any pre-processing
return data
},
group: [...]
}
fid for stable group identifiers — avoid index-based keysshowBtns: true); previous groups auto-hide buttonstitle{index} slots for custom group header styles (default: left border + text)modelValue objectdisabledTab: true to prevent Tab key from leaving the form on the last fieldel-plus-crud-form — ElPlusFormGroup creates ElPlusForm instances per group; all formDesc config applies (direct)el-plus-crud-config — IFormGroupConfig type definition (indirect)el-plus-crud-validation — cross-group parallel validation mechanism (indirect)Configuration system and TypeScript types for el-plus-crud — ICRUDConfig, IFormDesc, ITableConfig, provide/inject dependency injection
Dialog wrapper for ElPlusForm and ElPlusFormGroup with auto open/close, submit handling, and table reload coordination
Data-driven form component with 40+ field types, dynamic visibility, multi-column layout, submit lifecycle hooks, and field-level linking
Proven patterns and recipes for common CRUD scenarios — complete CRUD page, search-reset workflow, master-detail, custom components, and permission control
Vue 3 + Element Plus data-driven CRUD component library — entry skill for all components and configuration
Data-driven table component with multi-level headers, pagination, tabs, row selection, export, summary rows, and tree expansion