Skip to content

表单联动实现方案设计 #228

@MrWindlike

Description

@MrWindlike

表单联动

背景

在实现表单的交互中,我们往往需要实现一个表单项和其他表单项进行联动,来进行展示/隐藏其他表单项、修改其他表单项的值,或是触发其他表单项的校验等。

使用场景

  1. 展示/隐藏其他表单项

虽然当前我们提供 render 配置,支持在渲染函数中返回空来隐藏表单项,但这样隐藏还是会校验表单项,隐藏得不完全。

因此可以在表单配置中新增一个 condition 配置,在其函数内读取整个表单的值,来判断是否要展示当前表单项。

{
  name: 'field',
  condition(formValue, value): boolean {
    return get(formValue, 'someWatchedField') === 'someValue';
  }
}
  1. 修改其他表单项的值

实现这个需求有两种方法,一种是在触发联动的表单项中去修改其他表单项的值;另一种是在被联动的表单项中监听依赖的值,当依赖值变化时修改自己的值。

后者的代码逻辑会内聚在当前被联动的表单项中,会更容易排查所有会触发当前表单项值变动,所以我们使用后一种方法来实现。

目前已经支持实现该功能,无需对 dovetail v2 进行太大改动,只需要在 render 函数编写类似以下的逻辑:

import { renderCommonFormFiled, RefineFormFieldRenderProps } from '@dovetail-v2/refine';
import { useWatch } from 'react-hook-form';

function Field(props: RefineFormFieldRenderProps) {
  const { control, filed } = props;
  const { onChange } = field;
  // 监听依赖值的变动
  const watchedValue = useWatch({
    control,
    name: "watchedValue",
  })

  useEffect(()=> {
    // 当依赖赖变为特定值时,修改当前表单项的值
    if (watchedValue === 'someValue') {
      onChange('newValue');
    }
  }, [watchedValue])

  // 渲染为基础表单
  return renderCommonFormFiled(props);
}

{
  formType: FormType.FORM,
  fields() {
    return [
      path: ['field'],
      key: 'field',
      label: i18n.t('dovetail.field'),
      render(props) {
        return <Field {...props}/>
      }
    ];
  },
}
  1. 触发其他表单项校验

这个需求也已满足需求,react-hook-form 有提供 trigger 方法来触发当前/其他表单项的校验。

import { renderCommonFormFiled, RefineFormFieldRenderProps } from '@dovetail-v2/refine';
import { useWatch } from 'react-hook-form';

function Field(props: RefineFormFieldRenderProps) {
  const { control, filed, trigger } = props;
  const { onChange } = field;
  // 监听依赖值的变动
  const watchedValue = useWatch({
    control,
    name: "watchedValue",
  })

  useEffect(()=> {
    trigger('currentFieldName');
  }, [watchedValue])

  // 渲染为基础表单
  return renderCommonFormFiled(props);
}

{
  formType: FormType.FORM,
  fields() {
    return [
      path: ['field'],
      key: 'field',
      label: i18n.t('dovetail.field'),
      render(props) {
        return <Field {...props}/>
      }
    ];
  },
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions