Angular中Formio自定义文本组件层级审计改造遇阻求助
解决方案
核心思路是分离视图显示值与模型存储值:输入框仅展示value字段内容,模型层存储包含uid和value的完整对象,提交时直接输出模型数据。
修改后的组件代码如下:
import {Formio, Components} from "@formio/js"; // 生成UUID的工具函数(可根据需求替换) const generateUUID = () => { if (typeof crypto !== 'undefined' && crypto.randomUUID) { return crypto.randomUUID(); } // 兼容旧环境的简易UUID生成 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); }; const Base = Components.components.textfield; const editForm = Formio.Components.components.textfield.editForm; export class MyTextField extends Base { constructor(component: any, options: any, data: any) { // 初始化时处理默认值,转成带uid的对象 if (data && typeof data !== 'object') { data = { uid: generateUUID(), value: data }; } super(component, options, data); } static schema(...extend: any) { return Base.schema( { label: 'My Text Field', key: 'mytextField', type: 'mytextfield', }, ...extend ); } static builderInfo = { title: 'My Text Box', group: 'basic', icon: 'fa fa-table', weight: 70, documentation: '', schema: MyTextField.schema(), }; static editForm = editForm; // 重写getViewValue:返回输入框要显示的内容(仅取value字段) getViewValue() { const modelValue = super.getValue(); if (modelValue && typeof modelValue === 'object') { return modelValue.value ?? ''; } return modelValue || ''; } // 重写getValue:返回完整的模型数据(带uid和value) getValue() { const value = super.getValue(); // 兼容未初始化的情况,确保返回格式正确 if (!value) { return { uid: generateUUID(), value: '' }; } if (typeof value !== 'object') { return { uid: generateUUID(), value }; } // 确保uid存在,防止外部传入的对象缺失uid if (!value.uid) { value.uid = generateUUID(); } return value; } // 重写setValue:处理外部传入值,统一转成带uid的对象 setValue(value: any, flags = {}) { let modelValue; if (typeof value === 'object' && value !== null) { modelValue = { uid: value.uid || generateUUID(), value: value.value ?? '' }; } else { modelValue = { uid: generateUUID(), value: value || '' }; } super.setValue(modelValue, flags); } // 重写updateValue:用户输入时,更新模型为带uid的对象 updateValue(value: any, flags: any = {}, index?: any) { const modelValue = { uid: generateUUID(), value: value || '' }; super.updateValue(modelValue, flags, index); } // 修复原有的递归调用问题 setValueAt(index: any, value: any, flags = {}) { const modelValue = { uid: generateUUID(), value: value || '' }; super.setValueAt(index, modelValue, flags); } } // 注册组件 Components.addComponent('mytextfield', MyTextField);
关键修改说明
getViewValue:Formio组件用这个方法获取要渲染到输入框的内容,专门提取对象中的value字段,避免显示[object Object]。getValue:确保提交时返回完整的{uid, value}结构,同时兼容外部传入的原始值,自动补全uid。setValue/updateValue:无论外部传入的是原始值还是对象,都统一转换为符合要求的模型结构,同时生成唯一uid。- 构造函数初始化处理:组件初始化时,自动把原始默认值转成带uid的对象,保证数据格式一致。
- 修复
setValueAt递归问题:原代码错误调用自身,现在改为调用父类方法并传入处理后的模型值。
测试验证
- 在表单中添加自定义的
My Text Box组件,输入内容后,输入框正常显示文字。 - 提交表单时,查看提交数据,对应字段会是
{uid: "生成的UUID", value: "输入的内容"}格式。 - 编辑已有数据时,如果传入的是原始值,组件会自动补全uid;如果传入的是带uid的对象,会保留原有uid(可根据需求调整是否强制生成新uid)。
内容的提问来源于stack exchange,提问作者Steve Percival
相关产品推荐
相关产品推荐

