本文介绍如何使用 hideWhen、disableWhen 和 valueChange 实现字段的动态控制和联动。
dynamic-fields-overview.definition.ts
import * as v from 'valibot';
import { actions, disableWhen, hideWhen } from '@piying/view-angular-core';
import { map } from 'rxjs';
export const schema = v.object({
showExtra: v.boolean(),
extraField: v.pipe(
v.string(),
actions.attributes.set({ placeholder: '勾选上方开关后显示' }),
hideWhen({
listen: (fn) =>
fn({ list: [['..', 'showExtra']] }).pipe(map((item) => !item.list[0])),
}),
),
isActive: v.boolean(),
name: v.pipe(
v.string(),
actions.attributes.set({ placeholder: '勾选上方开关后启用编辑' }),
disableWhen({
listen: (fn) =>
fn({ list: [['..', 'isActive']] }).pipe(map((item) => !item.list[0])),
}),
),
});
export const model = {
showExtra: true,
extraField: '额外字段',
isActive: true,
name: '',
};
API 参考:参数说明等详细信息请见 hideWhen / disableWhen / valueChange API。
hideWhen 根据其他字段的值决定是否隐藏当前字段:
dynamic-hide-when.definition.ts
import * as v from 'valibot';
import { hideWhen } from '@piying/view-angular-core';
import { map } from 'rxjs';
export const schema = v.object({
showExtra: v.boolean(),
extraField: v.pipe(
v.string(),
hideWhen({
listen: (fn) =>
fn({ list: [['..', 'showExtra']] }).pipe(map((item) => !item.list[0])),
}),
),
});
export const model = { showExtra: true, extraField: '额外字段' };
当 showExtra 的值为 false 时,extraField 将被隐藏。
hideWhen 可同时控制 hidden 和 disabled:
dynamic-hide-disabled.definition.ts
import * as v from 'valibot';
import { hideWhen } from '@piying/view-angular-core';
import { map } from 'rxjs';
export const schema = v.object({
enable: v.boolean(),
name: v.pipe(
v.string(),
hideWhen({
disabled: true,
listen: (fn) =>
fn({ list: [['..', 'enable']] }).pipe(map((item) => !item.list[0])),
}),
),
});
export const model = { enable: true, name: '张三' };
此时当 enable 为 false 时,name 字段同时被隐藏和禁用。
disableWhen 根据其他字段的值决定是否禁用当前字段:
dynamic-disable-when.definition.ts
import * as v from 'valibot';
import { disableWhen } from '@piying/view-angular-core';
import { map } from 'rxjs';
export const schema = v.object({
isActive: v.boolean(),
name: v.pipe(
v.string(),
disableWhen({
listen: (fn) =>
fn({ list: [['..', 'isActive']] }).pipe(map((item) => !item.list[0])),
}),
),
});
export const model = { isActive: true, name: '张三' };
| 特性 |
disableWhen |
hideWhen({ disabled: true }) |
| 功能 |
仅控制 disabled |
同时控制 hidden + disabled |
| 适用场景 |
字段可见但不可编辑 |
字段不可见且不可编辑 |
详见 API: disableWhen。
valueChange 监听字段值变化但不产生副作用,可用于自定义联动逻辑:
dynamic-value-change.definition.ts
import * as v from 'valibot';
import { valueChange } from '@piying/view-angular-core';
export const schema = v.object({
source: v.string(),
target: v.pipe(
v.string(),
valueChange((fn) =>
fn({ list: [['..', 'source']] }).subscribe((value) => {
// 自定义逻辑:源字段变化时更新目标字段
}),
),
),
});
export const model = { source: '', target: '' };
详见 API: valueChange。
根据单选按钮的值切换显示不同表单区域:
dynamic-payment.definition.ts
import * as v from 'valibot';
import { hideWhen } from '@piying/view-angular-core';
import { map } from 'rxjs';
export const schema = v.object({
paymentMethod: v.picklist(['alipay', 'wechat', 'card']),
alipayAccount: v.pipe(
v.string(),
hideWhen({
listen: (fn) =>
fn({ list: [['..', 'paymentMethod']] }).pipe(
map((item) => item.list[0] !== 'alipay'),
),
}),
),
wechatAccount: v.pipe(
v.string(),
hideWhen({
listen: (fn) =>
fn({ list: [['..', 'paymentMethod']] }).pipe(
map((item) => item.list[0] !== 'wechat'),
),
}),
),
cardNumber: v.pipe(
v.string(),
hideWhen({
listen: (fn) =>
fn({ list: [['..', 'paymentMethod']] }).pipe(
map((item) => item.list[0] !== 'card'),
),
}),
),
});
export const model = {
paymentMethod: 'alipay',
alipayAccount: '',
wechatAccount: '',
cardNumber: '',
};
当表单已提交时禁用所有编辑字段:
dynamic-submitted.definition.ts
import * as v from 'valibot';
import { disableWhen } from '@piying/view-angular-core';
import { map } from 'rxjs';
export const schema = v.object({
isSubmitted: v.boolean(),
name: v.pipe(
v.string(),
disableWhen({
listen: (fn) =>
fn({ list: [['..', 'isSubmitted']] }).pipe(map((item) => item.list[0])),
}),
),
});
export const model = { isSubmitted: false, name: '张三' };
使用 valueChange + field.get() + updateValue() 实现多字段间的级联更新:
dynamic-cascade.definition.ts
import * as v from 'valibot';
import { valueChange } from '@piying/view-angular-core';
import { skip } from 'rxjs';
export const schema = v.object({
k1: v.boolean(),
k2: v.pipe(
v.boolean(),
valueChange((fn) => {
fn({ list: [['#', 'k1']] })
.pipe(skip(1))
.subscribe(({ list: [value], field }) => {
field.form.control?.updateValue(!value);
});
}),
),
k3: v.pipe(
v.boolean(),
valueChange((fn) => {
fn({ list: [['#', 'k2']] })
.pipe(skip(1))
.subscribe(({ list: [value], field }) => {
field.form.control?.updateValue(!value);
});
}),
),
});
export const model = { k1: true, k2: false, k3: true };
注意:首次监听时值为 undefined(除非设置了默认值),因此需要使用 skip(1) 跳过初始触发。
通过 valueChange 监听字段并更新其他字段:
dynamic-update-other.definition.ts
import * as v from 'valibot';
import { valueChange } from '@piying/view-angular-core';
export const schema = v.object({
mode: v.pipe(
v.picklist(['data1', 'data2']),
valueChange((fn) => {
fn().subscribe(({ list: [value], field }) => {
const o1FG = field.get(['#', 'o1']).form.control;
const o2FG = field.get(['#', 'o2']).form.control;
if (value === 'data1') {
o1FG.updateValue({ k1: 'data1-input-k1', k2: 'data1-input-k2' });
o2FG.updateValue({});
} else {
o2FG.updateValue({ k3: 'data2-input-k3', k4: 'data2-input-k4' });
o1FG.updateValue({});
}
});
}),
),
o1: v.object({ k1: v.optional(v.string()), k2: v.optional(v.string()) }),
o2: v.object({ k3: v.optional(v.string()), k4: v.optional(v.string()) }),
});
export const model = {
mode: 'data1',
o1: { k1: '', k2: '' },
o2: { k3: '', k4: '' },
};