React Help! - Stuck on how to conditionally render (and add to state) extra form options on checking dynamically generated check boxes in React

Hi, can anyone help, i’m trying this as a learning exercise in React but i’m really stuck.

I have 3 checkboxes on a child component that i have rendered dynamically using an array of options in state (in the parent component):

What i need to be able to do is, as per the below image: click on each checkbox and get further options.

The checked options and the sub options (not just dropdowns, the third checkbox has input fields) all need to be available in state so i can collect them up and post them to a database

What i have so far is the below:

Array of options in state:

sowType: [
    "ProductSow",
    "Teradata Customer SOW",
    "Custom Professional Services SOW"
  ]

Final rendered checkboxes:

image

My problem is, i don’t know what to do next. I have dynamically rendered the initial 3 check boxes but i don’t know how to add the conditional rendering to get the sub boxes to appear on clicking the check boxes) and add the info selected from them to state.

i.e. can i only add the conditional rendering on checkboxes that have NOT been dynamically rendered from map or is there a way to do it, in which case how is it done?

My code so far is as below, it may not be the best setup for what i am trying to do:

Can anyone help??

This is the reference to the component in the parent with the props passed down:

<SowType
        title={"SOW Type"}
        setName={"SOW Type"}
        subtitle={"What type of SOW do you want to generate?"}
        type={"checkbox"}
        controlFunc={this.handleSOWTypeCheckbox}
        options={this.state.sowType}
        selectedOptions={this.state.sowTypeSelectedOption}
      />

This is the child component dynamically rendering the array of items from state:

class SOWType extends React.Component {
render() {
// console.log(this.props);
return (
  <div className="form-group">
    <label htmlFor={this.props.name} className="form-label">
      {this.props.title}
      <h6>{this.props.subtitle}</h6>
    </label>
    <div className="checkbox-group">
      {this.props.options.map(option => {
        return (
          <label key={option}>
            <input
              className="form-checkbox"
              name={this.props.setName}
              onChange={this.props.controlFunc}
              value={option}
              checked={this.props.selectedOptions.indexOf(option) > -1}
              type={this.props.type}
            />
            {option}
          </label>
        );
      })}
    </div>
  </div>
  );
 }
}

This is the method i am currently using in the parent when a checkbox is clicked in the child component (this basically takes the selected option from the array in state and puts the checked options into another array in state called ‘sowTypeSelectedOption: ’,

handleSOWTypeCheckbox(e) {
const newSelection = e.target.value;
let newSelectionArray;

if (this.state.sowTypeSelectedOption.indexOf(newSelection) > -1) {
  newSelectionArray = this.state.sowTypeSelectedOption.filter(
    item => item !== newSelection
  );
} else {
  newSelectionArray = [...this.state.sowTypeSelectedOption, newSelection];
}
this.setState(
  {
    sowTypeSelectedOption: newSelectionArray
  } /*() =>
  console.log("sow Type Selection: ", this.state.sowTypeSelectedOption) */
);
}

Do you have this on codepen or codesandbox?

Hi, sandbox here: https://codesandbox.io/s/rlmv6ojjyn (have not yet figured out how to solve the original problem)

  • For reference, the form container is the file called:

    PdfGenFormContainer.js
    

The relevant child component is called:

   SOWType.js

I would recommend you use some conditional logic to render the next options based on the value.
I use this sort of statement but you have 3 conditions to test:

  render() {
    return (this.state.addMode) ? this.renderAddNewRecipe() : this.renderDisplay()
  }

Then I have separate functions for rendering different choices by the user.

You could possibly have the different options stored in PdfGenFormContainer and pass them down as props, depending on the user’s choice.
I have only had a quick look at your code but that is probably what I would try.

Hi, thanks for the response, I’ve read it a few times but i’m not really sure what you mean? What do addMode, renderAddNewRecipe and renderDisplay correspond to?

this.state.addMode is a flag that toggles what code will be rendered.
This is taken from my Recipe app

Ah ok, i think i see what you are saying i’ll take a look, thanks

1 Like

Have you received solution to this problem? If yes, Please do share. I have a similar requirement.
Thank you.

Hi thanujareddy, this link shows the discussion i had with someone on stackoverflow re coming up with a solution with just react: https://stackoverflow.com/questions/53741505/how-to-conditionally-render-extra-form-options-on-checking-dynamically-generated This solution mostly works but i still had an issue with updating state which i was unable to resolve.

I have recently been dabbling with redux-form. This add-on library enables you to use a redux store (separates state from any particular component so it’s easier when working worth multiple components) which has enabled me to get much further on this particular problem. When forms get very big and complicated it is not recommended to put form state in the redux store (each change to the form/update to state re-renders the form so you could imagine the performance hit) but this particular form was not big enough for it to be an issue. A sandbox of my redux-form version is as per this link: https://codesandbox.io/s/currying-cloud-isu8c

I think the ideal is update local component state then send just the final result to the redux store via an action but getting this to work was proving difficult with my current (limited) level of JavaScript skill

I hope something from the above helps you with your current issue