formengine icon indicating copy to clipboard operation
formengine copied to clipboard

general loadCallback function on loadData options

Open tulusibrahim opened this issue 1 year ago • 5 comments

i wonder is loadCallback can set to a specific form data/options for dropdown for example, like you used in this example

image

is there a way to do that like below

loadCallback(data, 'region')

this will set options of region input

tulusibrahim avatar Apr 29 '24 09:04 tulusibrahim

@tulusibrahim Hi!

Please explain what you intend to implement. What would be the end-user use case? To create dependent form fields with various options, refer to the comment below.

cherepanov avatar May 02 '24 14:05 cherepanov

You can use calculated value and get all fields data inside it.

Form code
{
  "version": "1",
  "actions": {
    "loadData": {
      "body": "\n    const [searchValue, loadCallback, currentDataLength] = e.args\n\n    fetch ('https://gist.githubusercontent.com/rogargon/5534902/raw/434445021e155240ca78e378f10f70391dd594ea/countries.json')\n        .then (data => data.json())\n        .then (data => {\n            const preparedData = data\n                .filter(value => value.toLowerCase().includes(searchValue.toLowerCase()))\n                .slice(currentDataLength, currentDataLength + 20)\n                .map(value => ({value, label: value}))\n\n            loadCallback(preparedData)        \n        })\n",
      "params": {}
    }
  },
  "form": {
    "key": "Screen",
    "type": "Screen",
    "props": {},
    "css": {
      "any": {
        "object": {},
        "string": "    text-align: left;"
      }
    },
    "children": [
      {
        "key": "CommaValues",
        "type": "RsInput",
        "props": {}
      },
      {
        "key": "status",
        "type": "RsDropdown",
        "props": {
          "label": {
            "value": "Status"
          },
          "data": {
            "computeType": "function",
            "fnSource": "// enter your code here\n    const sourceFiledValue = form?.fields?.get('CommaValues').value;\n    const dropdownOptions = (sourceFiledValue || '').split(/(?:,| |;)+/);\n\n    return dropdownOptions.map((v) => ({label: v, value: v}));"
          }
        },
        "wrapperCss": {
          "any": {
            "object": {}
          }
        },
        "htmlAttributes": []
      },
      {
        "key": "unit",
        "type": "RsDropdown",
        "props": {
          "label": {
            "value": "Unit"
          },
          "readOnly": {
            "computeType": "function",
            "value": false
          }
        },
        "events": {
          "onLoadData": [
            {
              "name": "loadData",
              "type": "code"
            }
          ]
        }
      },
      {
        "key": "remark",
        "type": "RsTextArea",
        "props": {
          "label": {
            "value": "Remark"
          },
          "size": {
            "value": "md"
          }
        }
      },
      {
        "key": "feedback",
        "type": "RsTextArea",
        "props": {
          "label": {
            "value": "Feedback"
          }
        }
      },
      {
        "key": "RsButton 1",
        "type": "RsButton",
        "props": {
          "children": {
            "value": "Submit"
          }
        },
        "events": {
          "onClick": []
        }
      }
    ]
  },
  "localization": {},
  "languages": [
    {
      "code": "en",
      "dialect": "US",
      "name": "English",
      "description": "American English",
      "bidi": "ltr"
    }
  ],
  "defaultLanguage": "en-US"
}

2024-05-02_17-39

cherepanov avatar May 02 '24 14:05 cherepanov

And the same inside Actions callback.

Form code ```json { "version": "1", "actions": { "loadData": { "body": "\n const [searchValue, loadCallback, currentDataLength] = e.args\n const statusValue = e.data['status'];\n\n alert(`Selected status: ${statusValue}`);\n\n fetch ('https://gist.githubusercontent.com/rogargon/5534902/raw/434445021e155240ca78e378f10f70391dd594ea/countries.json')\n .then (data => data.json())\n .then (data => {\n const preparedData = data\n .filter(value => value.toLowerCase().includes(searchValue.toLowerCase()))\n .slice(currentDataLength, currentDataLength + 20)\n .map(value => ({value, label: value}))\n\n loadCallback(preparedData) \n })\n", "params": { "staticArg": "string" } }, "test": { "body": " const foo = e.data['CommaValues'];\n debugger", "params": {} } }, "form": { "key": "Screen", "type": "Screen", "props": {}, "css": { "any": { "object": {}, "string": " text-align: left;" } }, "children": [ { "key": "CommaValues", "type": "RsInput", "props": {} }, { "key": "status", "type": "RsDropdown", "props": { "label": { "value": "Status" }, "data": { "computeType": "function", "fnSource": "// enter your code here\n const sourceFiledValue = form?.fields?.get('CommaValues').value;\n const dropdownOptions = (sourceFiledValue || '').split(/(?:,| |;)+/);\n\n return dropdownOptions.map((v) => ({label: v, value: v}));" } }, "wrapperCss": { "any": { "object": {} } }, "htmlAttributes": [], "events": { "onSearch": [] } }, { "key": "unit", "type": "RsDropdown", "props": { "label": { "value": "Unit" }, "readOnly": { "computeType": "function", "value": false } }, "events": { "onLoadData": [ { "name": "loadData", "type": "code" } ], "onSearch": [ { "name": "test", "type": "code" } ] } }, { "key": "remark", "type": "RsTextArea", "props": { "label": { "value": "Remark" }, "size": { "value": "md" } } }, { "key": "feedback", "type": "RsTextArea", "props": { "label": { "value": "Feedback" } } }, { "key": "RsButton 1", "type": "RsButton", "props": { "children": { "value": "Submit" } }, "events": { "onClick": [] } } ] }, "localization": {}, "languages": [ { "code": "en", "dialect": "US", "name": "English", "description": "American English", "bidi": "ltr" } ], "defaultLanguage": "en-US" } ```

2024-05-02_17-50

cherepanov avatar May 02 '24 14:05 cherepanov

@tulusibrahim Hi!

Please explain what you intend to implement. What would be the end-user use case? To create dependent form fields with various options, refer to the comment below.

i want to have one custom action to fetch all data needed (hit multiple external API) and set it to multiple input within the form. can i do it?

tulusibrahim avatar May 03 '24 09:05 tulusibrahim

@tulusibrahim

Yes, this is possible. Follow these steps:

  • Request data on the form level, inside onDidMount
  • Propagate it to the form's shared state.
  • Use the calculated value for component data.

The key here is e.store.formData.state, a shared object that you can access across all components.

async function Action (e, args) {
    fetch ('https://gist.githubusercontent.com/rogargon/5534902/raw/434445021e155240ca78e378f10f70391dd594ea/countries.json')
        .then (data => data.json())
        .then (data => {
            const preparedData = data.map(value => ({value, label: value}))

            e.store.formData.state.options = preparedData 
        })
}
function Calculation (form) {
    return form.state.options
}

Here is fixed example https://stackblitz.com/edit/vitejs-vite-djtftw

And minimal form definition
{
  "version": "1",
  "actions": {
    "test": {
      "body": "    const foo = e.data['CommaValues'];\n    debugger",
      "params": {}
    },
    "preloadData": {
      "body": "    fetch ('https://gist.githubusercontent.com/rogargon/5534902/raw/434445021e155240ca78e378f10f70391dd594ea/countries.json')\n        .then (data => data.json())\n        .then (data => {\n            const preparedData = data.map(value => ({value, label: value}))\n\n            e.store.formData.state.options = preparedData       \n        })",
      "params": {
        "staticArg": "string"
      }
    },
    "dng": {
      "body": "    // debugger\n    console.log(e.data)\n    console.log(e.state)\n    console.log(e.data.state)\n    debugger",
      "params": {}
    },
    "estersr": {
      "body": "    debugger\n    // e.sender.field.componentStore = e.store.form.state",
      "params": {}
    }
  },
  "form": {
    "key": "Screen",
    "type": "Screen",
    "props": {},
    "css": {
      "any": {
        "object": {},
        "string": "    text-align: left;"
      }
    },
    "events": {
      "onDidMount": [
        {
          "name": "preloadData",
          "type": "code",
          "args": {
            "staticArg": "123"
          }
        }
      ]
    },
    "children": [
      {
        "key": "status",
        "type": "RsDropdown",
        "props": {
          "label": {
            "value": "Status"
          },
          "data": {
            "computeType": "function",
            "fnSource": "    return form.state.options"
          }
        },
        "wrapperCss": {
          "any": {
            "object": {}
          }
        },
        "htmlAttributes": [],
        "events": {
          "onSearch": []
        }
      }
    ]
  },
  "localization": {},
  "languages": [
    {
      "code": "en",
      "dialect": "US",
      "name": "English",
      "description": "American English",
      "bidi": "ltr"
    }
  ],
  "defaultLanguage": "en-US"
}

cherepanov avatar May 03 '24 13:05 cherepanov