1

I have several checkbox groups on my Component of which only one of the should be selected. Each group has the same number of checkboxes (3 in the example), and the one selected is identified by the checked key inside the data list.

How can I handle this state?

class test extends Component {
  constructor(props) {
    super(props);
    this.state = {};
    const data = [
      { name: orange, checked: 2 },
      { name: apple, checked: 3 },
      { name: banana, checked: 1 }
    ];
  }

  render() {
    return (
      <>
        {data.map(items => (
          <tr>
            <td>{items.name}</td>
            <td>
              <div>
                <input type="checkbox" value="1" checked={true} />
              </div>
            </td>
            <td>
              <div>
                <input type="checkbox" value="2" checked={false} />
              </div>
            </td>
            <td>
              <div>
                <input type="checkbox" value="3" checked={false} />
              </div>
            </td>
          </tr>
        ))}
      </>
    );
  }
}

Component example

1
  • Hi james, just wrote you a solution below, please comment and let me know your thoughts. Commented Jul 22, 2019 at 2:44

2 Answers 2

4

Try organizing your data-structure to look something like this:

  data: [
    { name: "orange", boxes: [1, 2, 3], selected: null },
    { name: "apple", boxes: [1, 2, 3], selected: null },
    { name: "pineapple", boxes: [1, 2, 3], selected: null }
  ]

That gives us a group-name, an array of values to choose from and a selected value. We'll be manipulating that data via our component-state.

Here's a codesandbox for reference: https://codesandbox.io/s/gallant-paper-b1d4z

Working code:

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: [
        { name: "orange", boxes: [1, 2, 3], selected: null },
        { name: "apple", boxes: [1, 2, 3], selected: null },
        { name: "pineapple", boxes: [1, 2, 3], selected: null }
      ]
    };
  }

  handleOnChange = e => {
    const { data } = this.state;
    const { name, value } = e.target;
    const updatedData = data.map(group => {
      if (group.name === name) {
        return {
          ...group,
          selected: group.selected === value ? null : value
        };
      } else {
        return group;
      }
    });

    this.setState({ data: updatedData }, () => console.log(this.state));
  };

  createInputGroups = () => {
    const { data } = this.state;
    const groups = data.map(group => {
      return (
        <div style={{ display: "flex" }}>
          <div>{group.name}</div>
          <div>
            {group.boxes.map(box => {
              return (
                <input
                  onChange={this.handleOnChange}
                  type="checkbox"
                  name={group.name}
                  value={box}
                  checked={group.selected == box}
                />
              );
            })}
          </div>
        </div>
      );
    });
    return groups;
  };

  render() {
    return <div>{this.createInputGroups()}</div>;
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Pleases excuse my CSS :)

Sign up to request clarification or add additional context in comments.

Comments

2

You can check at the checked option if the value of the checkbox is the same as the checked value of your item interface. Check this component as an example:

function CheckboxGroupRow({ name, checked, onUpdate }) {
  return (
    <tr className="CheckboxGroup">
      <td>{name}</td>
      <td>
        <input
          type="checkbox"
          value={1}
          checked={checked === 1}
          onChange={e => onUpdate({ name, checked: +e.target.value })}
        />
      </td>
      <td>
        <input
          type="checkbox"
          value={2}
          checked={checked === 2}
          onChange={e => onUpdate({ name, checked: +e.target.value })}
        />
      </td>
      <td>
        <input
          type="checkbox"
          value={3}
          checked={checked === 3}
          onChange={e => onUpdate({ name, checked: +e.target.value })}
        />
      </td>
    </tr>
  );
}

Each checkbox has a value, and it's checked only if the value of the checked variable matches to the one on the checkbox. For the onChange handle I have an onUpdate function that will be called with an updated data item whenever a user clicks a checkbox. Some logic upstream should handle the update.

Please take a look at this example build on CodeSandbox:

https://codesandbox.io/embed/checkboxgroup-cyv4p

I hope it helps

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.