optimajet / formengine

Drag & Drop Form Builder Library for React.
https://formengine.io
31 stars 5 forks source link

Recursive calculation causing input problems #28

Closed Sarim-Sohail closed 2 months ago

Sarim-Sohail commented 2 months ago

I have a simple task, I have 2 dropdowns.

When I select A in one, I want B to show in the other, and vice versa. However, this is not possible to do in the demo website itself:

image

When initially setting the value of the first dropdown to A, the second one becomes B. When modifying the second dropdown to either A or B, it works as expected. However the first dropdown is not possible to change on it's own, and it doesn't change the value of the second dropdown. By logging the form.data in console I can see it's trying to change it, but the logic is recursively calling itself to the point where it's overriding the input. I can't differentiate the input attempts using anything the form parameter passes me.

I also tried this using the onChange function, but I can't get the data of the second input box directly, and I have about ~50 rows of these inputs to make, which makes individually coding them a hassle.

Is there any solution available?

Here's my form data:

{
  "version": "1",
  "actions": {
    "test": {
      "body": "    console.log(e, \"TEST\", args);",
      "params": {
        "prop1": "string"
      }
    }
  },
  "form": {
    "key": "Screen",
    "type": "Screen",
    "props": {},
    "children": [
      {
        "key": "dd1",
        "type": "RsDropdown",
        "props": {
          "value": {
            "computeType": "function",
            "fnSource": "  console.log(\"DD1\", form.data);\n  if(form.data.dd2 === \"a\" )\n  {\n    return \"b\";\n  }\n  else if (form.data.dd2 === \"b\" )\n  {\n    return \"a\";\n  }\n  else \n  {\n    return form.data.dd1;\n  }"
          },
          "data": {
            "value": [
              {
                "value": "a",
                "label": "A"
              },
              {
                "value": "b",
                "label": "B"
              }
            ]
          }
        },
        "events": {
          "onSelect": [],
          "onChange": []
        }
      },
      {
        "key": "dd2",
        "type": "RsDropdown",
        "props": {
          "value": {
            "computeType": "function",
            "fnSource": "  console.log(\"DD2\", form.data);\n\n  if(form.data.dd1 === \"a\" )\n  {\n    return \"b\";\n  }\n  else if (form.data.dd1 === \"b\" )\n  {\n    return \"a\";\n  }\n  else \n  {\n    return form.data.dd2;\n  }\n"
          },
          "data": {
            "value": [
              {
                "value": "a",
                "label": "A"
              },
              {
                "value": "b",
                "label": "B"
              }
            ]
          },
          "readOnly": {
            "computeType": "function",
            "fnSource": " ",
            "value": false
          }
        },
        "events": {
          "onChange": []
        }
      }
    ]
  },
  "localization": {},
  "languages": [
    {
      "code": "en",
      "dialect": "US",
      "name": "English",
      "description": "American English",
      "bidi": "ltr"
    }
  ],
  "defaultLanguage": "en-US"
}
optimajet commented 2 months ago

@Sarim-Sohail

When initially setting the value of the first dropdown to A, the second one becomes B. When modifying the second dropdown to either A or B, it works as expected.

You have been created a cyclic dependency, which of course will cause the data to change ad infinitum.

You can define an action with parameters, and then define arguments when linking actions:

image

Example:

{
  "version": "1",
  "actions": {
    "modifyAnotherDropdown": {
      "body": "  const value = e.args[0]\n  if (value === 'a') {\n    e.data[args.destKey] = 'b'\n  }\n  if (value === 'b') {\n    e.data[args.destKey] = 'a'\n  }",
      "params": {
        "sourceKey": "string",
        "destKey": "string"
      }
    }
  },
  "form": {
    "key": "Screen",
    "type": "Screen",
    "props": {},
    "children": [
      {
        "key": "dd1",
        "type": "RsDropdown",
        "props": {
          "value": {
            "fnSource": "  console.log(\"DD1\", form.data);\n  if(form.data.dd2 === \"a\" )\n  {\n    return \"b\";\n  }\n  else if (form.data.dd2 === \"b\" )\n  {\n    return \"a\";\n  }\n  else \n  {\n    return form.data.dd1;\n  }"
          },
          "data": {
            "value": [
              {
                "value": "a",
                "label": "A"
              },
              {
                "value": "b",
                "label": "B"
              }
            ]
          }
        },
        "events": {
          "onSelect": [],
          "onChange": [
            {
              "name": "modifyAnotherDropdown",
              "type": "code",
              "args": {
                "sourceKey": "dd1",
                "destKey": "dd2"
              }
            }
          ]
        }
      },
      {
        "key": "dd2",
        "type": "RsDropdown",
        "props": {
          "value": {
            "fnSource": "  console.log(\"DD2\", form.data);\n\n  if(form.data.dd1 === \"a\" )\n  {\n    return \"b\";\n  }\n  else if (form.data.dd1 === \"b\" )\n  {\n    return \"a\";\n  }\n  else \n  {\n    return form.data.dd2;\n  }\n"
          },
          "data": {
            "value": [
              {
                "value": "a",
                "label": "A"
              },
              {
                "value": "b",
                "label": "B"
              }
            ]
          },
          "readOnly": {
            "computeType": "function",
            "fnSource": " ",
            "value": false
          }
        },
        "events": {
          "onChange": [
            {
              "name": "modifyAnotherDropdown",
              "type": "code",
              "args": {
                "sourceKey": "dd2",
                "destKey": "dd1"
              }
            }
          ],
          "onSelect": []
        }
      }
    ]
  },
  "localization": {},
  "languages": [
    {
      "code": "en",
      "dialect": "US",
      "name": "English",
      "description": "American English",
      "bidi": "ltr"
    }
  ],
  "defaultLanguage": "en-US"
}
Sarim-Sohail commented 2 months ago

Thank you for the information, I appreciate it greatly