'Is there a way to handle state in a form that is dynamically built based off of parameters sent from the back end

I have a page in react 18 talking to a server which is passing information about how to build specific elements in a dynamic form. I am trying to figure out how to manage state in a case where there are multiple selects/multiselects in the page. Using one hook will not work separately for each dropdown field.

Code is updated with the latest updates. Only having issues with setting default values at this point. Hooks will not initially set values when given.

        import { Calendar } from 'primereact/calendar';
import { Dropdown } from 'primereact/dropdown';
import { InputSwitch } from 'primereact/inputswitch';
import { InputText } from 'primereact/inputtext';
import { MultiSelect } from 'primereact/multiselect';
import React, { useEffect, useState, VFC } from 'react';
import { useLocation } from 'react-router-dom';
import { useEffectOnce } from 'usehooks-ts';

import { useAppDispatch, useAppSelector } from 'redux/store';

import Form from '../components/ReportViewForm/Form';
import { getReportParamsAsync, selectReportParams } from '../redux/slice';

export const ReportView: VFC = () => {
  const location = useLocation();
  const locState = location.state as any;
  const dispatch = useAppDispatch();
  const reportParams = useAppSelector(selectReportParams);
  const fields: JSX.Element[] = [];
  const depList: any[] = [];
  //const defaultValList: any[] = [];

  //dynamically setting state on all dropdown and multiselect fields
  const handleDdlVal = (name: string, value: string) => {
    depList.forEach((dep) => {
      if (name === dep.dependencies[0]) {
        dispatch(getReportParamsAsync(currentMenuItem + name + value));
      }
    });
    setState((prev: any) => {
      return { ...prev, [name]: value };
    });
  };
  //dynamically setting state on all calendar fields
  const handleCalVal = (name: string, value: Date) => {
    setState((prev: any) => {
      return { ...prev, [name]: value };
    });
  };
  //dynamically setting state on all boolean fields
  const handleBoolVal = (name: string, value: boolean) => {
    setState((prev: any) => {
      return { ...prev, [name]: value };
    });
  };

  /*   function getInitVals(values: any) {
    const defaultList: any[] = [];
    values.forEach((param: any) => {
      defaultList.push({ name: param.name, value: param.defaultValues[0] });
    });
  } */

  const [state, setState] = useState<any>({});

  const [currentMenuItem, setCurrentMenuItem] = useState(locState.menuItem.id.toString());
  useEffectOnce(() => {}), [];

  useEffect(() => {
    if (reportParams?.length === 0) {
      dispatch(getReportParamsAsync(currentMenuItem));
    }
    //reload hack in order to get page to load correct fields when navigating to another report view
    if (currentMenuItem != locState.menuItem.id) {
      window.location.reload();
      setCurrentMenuItem(locState.menuItem.id.toString());
    }
  }, [dispatch, reportParams, currentMenuItem, locState, state]);

  //dependency list to check for dependent dropdowns, passed to reportddl
  reportParams.forEach((parameter: any) => {
    if (parameter.dependencies !== null && parameter.dependencies[0] !== 'apu_id') {
      depList.push(parameter);
    }
  });

  //filter dispatched data to build correct fields with data attached.
  reportParams.forEach((parameter: any, i: number) => {
    if (parameter.validValuesQueryBased === true) {
      if (parameter.validValues !== null && parameter.multiValue) {
        const dataList: any[] = [];
        parameter.validValues.map((record: { value: any; label: any }) =>
          dataList.push({ id: record.value, desc: record.label }),
        );
        fields.push(
          <span key={i} className='p-float-label col-12 mx-3 field'>
            <MultiSelect
              options={dataList}
              name={parameter.name}
              value={state[parameter.name]}
              onChange={(e) => handleDdlVal(parameter.name, e.value)}
            ></MultiSelect>
            <label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
          </span>,
        );
      } else if (parameter.validValues !== null) {
        const dataList: any[] = [];
        parameter.validValues.map((record: { value: any; label: any }) =>
          dataList.push({ id: record.value, desc: record.label }),
        );
        fields.push(
          <span key={i} className='p-float-label col-12 mx-3 field'>
            <Dropdown
              options={dataList}
              optionValue='id'
              optionLabel='desc'
              name={parameter.name}
              onChange={(e) => handleDdlVal(parameter.name, e.value)}
              value={state[parameter.name]}
              //required={parameter.parameterStateName}
              placeholder={'Select a Value'}
            ></Dropdown>
            <label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
          </span>,
        );
      }
    } else if (parameter.parameterTypeName === 'Boolean') {
      fields.push(
        <span key={i} className='col-12 mx-3 field-checkbox'>
          <InputSwitch
            checked={state[parameter.name]}
            id={parameter.id}
            name={parameter.name}
            onChange={(e) => handleBoolVal(parameter.name, e.value)}
          ></InputSwitch>
          <label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
        </span>,
      );
    } else if (parameter.parameterTypeName === 'DateTime') {
      //const date = new Date(parameter.defaultValues[0]);
      fields.push(
        <span key={i} className='p-float-label col-12 mx-3 field'>
          <Calendar
            value={state[parameter.name]}
            name={parameter.name}
            onChange={(e) => {
              const d: Date = e.value as Date;
              handleCalVal(parameter.name, d);
            }}
          ></Calendar>
          <label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
        </span>,
      );
    } else if (parameter.name === 'apu_id') {
      return null;
    } else {
      fields.push(
        <span key={i} className='p-float-label col-12 mx-3 field'>
          <InputText name={parameter.name}></InputText>
          <label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
        </span>,
      );
    }
  });

  const onSubmit = () => {
    console.log(state);
  };

  return (
    <Form onReset={null} onSubmit={onSubmit} initialValues={null} validation={null} key={null}>
      {fields}
    </Form>
  );
};

enter code here


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source