You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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递归问题:原代码错误调用自身,现在改为调用父类方法并传入处理后的模型值。

测试验证

  1. 在表单中添加自定义的My Text Box组件,输入内容后,输入框正常显示文字。
  2. 提交表单时,查看提交数据,对应字段会是{uid: "生成的UUID", value: "输入的内容"}格式。
  3. 编辑已有数据时,如果传入的是原始值,组件会自动补全uid;如果传入的是带uid的对象,会保留原有uid(可根据需求调整是否强制生成新uid)。

内容的提问来源于stack exchange,提问作者Steve Percival

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 10:25:14