跳转到内容

值转换与联动

本文介绍如何使用 transformer 和 Valibot 的 transform Action 实现视图层与模型层的值转换。

formConfig.transformer 提供两个转换钩子:

方法 方向 说明
toView 模型 → 视图 存入模型的原始值转换为视图显示值
toModel 视图 → 模型 用户输入的值转换为存入模型的值

formConfig.pipe.toModel 使用 RxJS Observable 进行值转换,支持去抖、过滤等操作:

以下示例节选自单元测试(createBuilder / delay 为测试内部工具,非公开 API;实际项目中用 convertToField 构建字段即可)。

import { map, pipe } from 'rxjs';
import { formConfig } from '@piying/view-angular-core';

const obj = v.pipe(
  v.string(),
  formConfig({
    pipe: {
      toModel: pipe(map((item) => `${item}1`)),
    },
  }),
);

const result = createBuilder(obj);
result.form.control!.viewValueChange('2');
expect(result.form.control!.value).toEqual('21'); // ✅ toModel 转换生效
import { debounceTime, pipe } from 'rxjs';

const obj = v.pipe(
  v.string(),
  formConfig({
    pipe: {
      toModel: pipe(debounceTime(1)),
    },
  }),
);

const result = createBuilder(obj);
result.form.control!.viewValueChange('1');
// 去抖期间值未更新
expect(result.form.control!.value).not.toEqual('1');
// 等待去抖完成后值生效
await delay(2);
expect(result.form.control!.value).toEqual('1');
import { filter, pipe } from 'rxjs';

const obj = v.pipe(
  v.string(),
  formConfig({
    pipe: {
      toModel: pipe(filter((item) => item === '1')),
    },
  }),
);

const result = createBuilder(obj);
result.form.control!.viewValueChange('1'); // 通过过滤
result.form.control!.viewValueChange('2'); // 被过滤掉

expect(result.form.control!.value).toEqual('1'); // ✅ 只有 '1' 生效

Valibot 内置的 v.transform() 在 Schema 层面进行值转换,Piying-View 会保留此行为:

将嵌套对象展平为单个字段:

特性 formConfig.transformer v.transform()
作用层 Form Control 配置 Valibot Schema
toView ✅ 支持 ❌ 不支持(需 v.transform 反向)
toModel ✅ 支持 ✅ 支持(等价于 toModel)
Pipe 支持 ✅ 完整 RxJS 管道 ❌ 不支持
适用场景 UI/模型双向转换 Schema 类型验证 + 转换

视图 → 模型(View → Model)完整链路

Section titled “视图 → 模型(View → Model)完整链路”
flowchart LR
    A[视图变更] --> B{值是否禁用?}
    B -->|| C[不发射值]
    B -->|| D[触发变更]
    D --> E[RxJS pipe.toModel 处理]
    E --> F[toModel transformer]
    F --> G[Valibot 解析验证]
    G --> H{验证通过?}
    H -->|失败| I[写入验证异常,标记 dirty]
    H -->|成功| J[设置表单值]
    I --> K[跳过发射]
    J --> L[触发 valueChanges]
    L --> M[异步获取值后发射]

模型 → 视图(Model → View)完整链路

Section titled “模型 → 视图(Model → View)完整链路”
flowchart LR
    A[根级 updateValue] --> B[分发到 FieldControl]
    B --> C{视图是否变更?}
    C -->|| D[强制更新]
    C -->|| E[仅与上次不同才更新]
    D --> F[toView transformer]
    E --> F
    F --> G[视图渲染新值]