javascript - Dynamiskt formulär i Reactjs


Jag genererar formuläret baserat på data från API:et.

Formulärdata: (API returnerar en array av objekt men i mitt exempel har jag konverterat det till JSON för bättre förståelse men data är en array av objekt som nedan)

  [
    {
      "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"
    }
  ]

Så baserat på dessa data behöver jag skapa ett formulär. Och skapandet av formulär fungerar redan enligt det nedan angivna exemplet.

Krav:

Scenario 1:

Användaren väljer vaccinerad som ett alternativ från den första rullgardinsmenyn, då visas rullgardinsmenyn med data som Dos Ett och Dos Två. Om användaren sedan väljer någon av doserna måste han lägga till detaljer om den respektive dosen.

Scenario 2: (Arbetar nu)

Användaren väljer Inte vaccinerad som ett alternativ från den första rullgardinsmenyn, och då kommer orsak-rullgardinsmenyn att visas.

Scenario 3: (Fungerar nu)

Användaren väljer Annat som ett alternativ från den första rullgardinsmenyn, då kommer moreDetails-textfältet att visas.

Teknisk krav:

För att uppnå dessa villkorskontroller har jag inkluderat flera if..else..if-villkor som,

  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"
      ]);
    }
  }

Så till exempel, om mitt formulär växer och i den första rullgardinsmenyn om fler alternativ läggs till, då efter att ha valt ett alternativ från den första rullgardinsmenyn, visas den andra välj-/inmatningsrutan. Om den andra är en rullgardinsmeny, baserat på den visas nästa välj-/inmatningsruta och så vidare.

I det ovan givna exemplet, överväg vaccination. När användaren väljer vaccination visas dosesvalsrutan, och efter dosen visas inmatningsrutan för respektive dosdetaljer. (Så att det ena beror på det andra är kravet).

Arbets Exempel:

Hur kan vi ta bort denna flera if...else...if-villkorskontroll med hårdkodade värden och göra den konfigurerbar, kanske genom att ändra den ursprungliga datastrukturen eller på något annat sätt?

Var snäll och forka den givna codesandboxen och ge en lösning som skulle uppskattas mycket mer.

Svar #1

Jag tror att du bara behöver lägga till en "hiddenField"-nyckel som innehåller alla nycklar som behöver döljas när fältvärdet har ändrats.

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

Och sedan ändrar vi hela din if..else-kod till detta

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

Här är ett exempel

Svar #2

om du behöver en "egen lösning" finns det för många sätt att uppnå det.

kanske är detta lilla exempel användbart för dig, men du måste utveckla det vidare.

data :

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

och kod:

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 )
     ...

Dessutom kan varje egenskap automatiseras: om ( typeof Properties.[counter] ) ...

Relaterade artiklar