【问题标题】:Dynamic form in ReactjsReactjs 中的动态表单
【发布时间】:2022-01-03 18:02:39
【问题描述】:

我正在根据来自 API 的数据生成表单。

表单数据:(Api 返回对象数组,但在我的示例中,我已将其转换为 JSON 以便更好地理解,但数据是对象数组,如下所示)

  [
    {
      "id": "formDescription",
      "label": "Form Description",
      "type": { "name": "text" },
      "value": {
        "value": "Use this request for vaccination status",
        "type": {
          "name": "string"
        }
      },
      "properties": { "viewOnly": "true" },
      "typeName": "text"
    },
    {
      "id": "vaccinated",
      "label": "Vaccinated",
      "type": {
        "values": {
          "vaccinated": "Vaccinated",
          "not_vaccinated": "Not Vaccinated"
        },
        "name": "enum"
      },
      "value": {
        "value": null,
        "type": {
          "name": "string"
        }
      },
      "validationConstraints": [],
      "properties": { "groupName": "Letter Details" },
      "typeName": "enum"
    },
    {
      "id": "dose",
      "label": "Dose",
      "type": {
        "values": {
          "dose_one": "Dose One",
          "dose_two": "Dose Two"
        },
        "name": "enum"
      },
      "value": {
        "value": null,
        "type": {
          "name": "string"
        }
      },
      "validationConstraints": [],
      "properties": { "groupName": "Letter Details" },
      "typeName": "enum"
    },
    {
      "id": "reason",
      "label": "Reason",
      "type": { "name": "string" },
      "value": {
        "value": null,
        "type": {
          "name": "string"
        }
      },
      "validationConstraints": [],
      "properties": { "groupName": "Letter Details", "maxlength": "50" },
      "typeName": "string"
    },
    {
      "id": "doseOneDetails",
      "label": "Dose One Details",
      "type": { "name": "textArea" },
      "defaultValue": null,
      "value": {
        "value": null,
        "type": {
          "name": "string"
        }
      },
      "validationConstraints": [
        { "name": "maxlength", "config": "400", "validator": null }
      ],
      "properties": { "groupName": "Letter Details", "maxlength": "400" },
      "typeName": "textArea"
    },
    {
      "id": "doseTwoDetails",
      "label": "Dose Two Details",
      "type": { "name": "textArea" },
      "defaultValue": null,
      "value": {
        "value": null,
        "type": {
          "name": "string"
        }
      },
      "validationConstraints": [
        { "name": "maxlength", "config": "400", "validator": null }
      ],
      "properties": { "groupName": "Letter Details", "maxlength": "400" },
      "typeName": "textArea"
    }
  ]

所以我需要根据这些数据生成一个表单。并且表单的生成已经按照下面提供的示例进行。

要求:

场景 1:

用户从第一个选择框中选择vaccinated 作为选项,然后出现数据为Dose OneDose Two 的选择框。然后,如果用户选择任何剂量,那么他需要添加相应剂量的详细信息。

场景 2:(正在工作)

用户从第一个选择框中选择Not Vaccinated作为选项,然后将显示reason选择框。

场景 3:(正在工作)

用户从第一个选择框中选择Other作为选项,然后将显示moreDetails文本框。

技术要求:

为了实现这种条件检查,我包含了多个 if..else..if 条件,例如,

  if (Array.isArray(name) && name.length) {
    const [fieldName] = name;
    if (fieldName === "vaccination_status" && value === "vaccinated") {
      setFieldsToHide(["reason", "moreDetails"]);
    } else if (
      fieldName === "vaccination_status" &&
      value === "not_vaccinated"
    ) {
      setFieldsToHide([
        "dose",
        "doseOneDetails",
        "doseTwoDetails",
        "moreDetails"
      ]);
    } else if (fieldName === "vaccination_status" && value === "other") {
      setFieldsToHide([
        "reason",
        "dose",
        "doseOneDetails",
        "doseTwoDetails"
      ]);
    }
  }

因此,例如,如果我的表单增长并且在第一个选择框中添加了更多选项,那么在从第一个选择框中选择一个选项后,将显示第二个选择/输入框。如果第二个是选择框,则再次基于该选择/输入框显示并继续。

在上面给出的示例中,考虑接种疫苗。用户选择疫苗接种后,会显示剂量选择框,然后在剂量后显示相应的剂量详细信息输入框。 (所以一个依赖另一个是需求)。

工作示例:

我们如何才能通过修改原始数据结构或其他方式来删除这种带有硬编码值的多个if...else...if 条件检查并使其可配置?

请分叉给定的代码框并提供解决方案,我将更加感激。

【问题讨论】:

  • 查看jsonforms.io,看看它是否符合您的需求,而不是推出您自己的解决方案。无论如何,我强烈建议阅读(并利用)JSON 模式规范。它支持条件子模式和 if-else 属性,即可以根据其他字段或值有条件地包含或排除字段。 json-schema.org/understanding-json-schema/reference/…
  • @jered,感谢您的回复。我被指示使用我自己的解决方案来实现结果为此包括任何其他额外/第三方。但我是这种实现的初学者,所以停留在这一点上。解决上述问题的任何解决方案都会对我有很大帮助。
  • JSON Schema 不是一个好的解决方案。我说这是运行 JSON Schema 项目本身的人之一。在没有任何第三方工具的情况下构建动态表单生成是一项挑战,但可以做到。您可以使用 JSON Schema 来构建条件检查系统,而无需使用它来生成表单。
  • @Relequestual,感谢您的回复。对于这种情况,您有其他选择吗?如果可能的话,你能给我一个合适的解决方案吗?我是这方面的初学者,我已被重定向到 JSON 模式,但现在我知道这不是一个解决方案。所以任何好的解决方案都会真正帮助我更好地理解。谢谢。
  • 不幸的是没有。这是一项复杂的任务,您要求它在您现有的代码库中工作。如果您不愿意使用现有的库,听起来您有其他我们不知道或您无法分享的要求。我会回到要求你这样做的人那里寻求帮助和澄清要求。

标签: javascript reactjs typescript forms if-statement


【解决方案1】:

我认为您只需要添加一个“hiddenField”键,其中包含在字段值更改时需要隐藏的所有键。

[
 ...
 {
    "hiddenField": {
    "vaccinated": ["reason", "moreDetails"],
    "not_vaccinated": [
      "dose",
      "doseOneDetails",
      "doseTwoDetails",
      "moreDetails"
    ],
    "other": ["reason", "dose", "doseOneDetails", "doseTwoDetails"]
    }
 }
...
]

然后我们将您的整个 if..else 代码更改为此

  if (Array.isArray(name) && name.length) {
    const [fieldName] = name;
    if (fieldName === "vaccination_status") {
      setFieldsToHide((data[1] as any).hiddenField[value]);
    }
  }

Here is an example

【讨论】:

  • 这一行fieldName === "vaccination_status" 包含硬编码值(vaccination_status),这是我需要忽略的第一件事。此外,如果用户选择接种疫苗,那么我需要显示剂量选择框和之后选择任何特定剂量,然后需要显示相应的剂量详细信息输入。为了在此处简短说明,每个输入字段都依赖于另一个字段,依此类推,这需要是动态的..
  • 好的,我想你只需要替换你的 if...else 代码。因此,您需要检查该对象是否具有属性“hiddenField”,以便在输入更改时隐藏字段,以使其可重用于其他输入。如果您希望每个输入字段依赖于其他字段,您只需要创建“showField”属性以在“hiddenField”上显示具有相同技术的字段
【解决方案2】:

如果您需要“自己的解决方案”,那么实现它的方法太多了。

这个小例子可能对你有用,但你必须进一步开发它。

数据:

"properties": { "groupName": "Letter Details", "maxlength": "400", "display": {"equals": ["vaccinated", "not_vaccinated", "none", "inherits"]} } 

和代码:

if ( typeof Properties.display === "string" )
  setProperty("display",Properties.display);
else if ( typeof Properties.display === "object" )
  if( Properties.display.equals )
    setProperty("display", getFormValue(Properties.display.equals[0]) ===  Properties.display.equals[1] ? Properties.display.equals[2] : Properties.display.equals[3]
  else if( Properties.display.less_than )
     ...

此外,每个属性都可以自动化:if ( typeof Properties.[counter] ) ...

【讨论】:

  • 你有像代码沙箱这样的工作示例吗?
【解决方案3】:

您可以在 demo.tsx 中尝试(您可以重命名和更改参数以获得更好的效果)

import React, { useState, useCallback, useEffect } from "react";
import { GeneratedForm } from "./GenerateForm/GenerateForm";
import { FieldData } from "rc-field-form/lib/interface";
const jsonData = require("./data.json");
const loadData = () => JSON.parse(JSON.stringify(jsonData));

const objHide = {
  vaccinated: ["reason", "moreDetails"],
  not_vaccinated: ["dose", "doseOneDetails", "doseTwoDetails", "moreDetails"],
  other: ["dose", "doseOneDetails", "doseTwoDetails", "reason"]
};

function Demo() {
  const [data, setData] = useState([]);

  const [fieldsToHide, setFieldsToHide] = useState<string[]>([
    "reason",
    "dose",
    "doseOneDetails",
    "doseTwoDetails",
    "moreDetails"
  ]);

  useEffect(() => {
    if (data.length === 0) {
      setData(loadData().data);
    }
  }, [data]);

  const onFieldsChange = useCallback(
    (changedFields: FieldData[], allFields: FieldData[]) => {
      const valueSelected = changedFields[0].value;
      const hideArray = objHide[valueSelected];
      setFieldsToHide(hideArray);
    },
    []
  );

  return (
    <GeneratedForm
      formData={data}
      onFieldsChange={onFieldsChange}
      fieldsToHide={fieldsToHide}
    />
  );
}

export default Demo;

【讨论】:

  • 如果我们选择 vaccinated 作为选项,则显示与疫苗接种相关的所有输入。要求是一旦选择了疫苗接种状态,就需要选择剂量值,如果选择了,则会显示相应的剂量详细信息输入。这就是流程将如何进行的。
猜你喜欢
  • 2021-08-11
  • 2020-09-08
  • 2017-07-21
  • 1970-01-01
  • 2020-03-24
  • 2020-05-11
  • 2016-04-09
  • 2019-01-06
  • 2019-01-23
相关资源
最近更新 更多