'Get user roles input using checkboxes and save in an array using useState() in react

I am creating an admin page where the admin can assign roles to other users. For this, I'm creating a front end input with checkboxes:

role options

Now based on the options that the admin selects on front end, i want to send the roles data to backend in form of an array:

roles: ['admin', 'seller']

useState should be able to add / remove items to this array based on whether the associated cell is checked or unchecked.

const [roles, setRoles] = useState([]);

const checkBoxInputs = [
{
  id: 1,
  label: 'Admin',
  value: 'admin',
},
{
  id: 2,
  label: 'Seller',
  value: 'seller',
},
{
  id: 3,
  label: 'User',
  value: 'user',
},
];

const [isChecked, setIsChecked] = useState(false);
const [roles, setRoles] = useState([]);

const handleCheckboxChange = (e) => {
  setIsChecked(!isChecked);
  if (isChecked) {
    setRoles([...roles, roles.push(e.target.value)]);
  } else {
    setRoles([roles.filter(e.target.value)]);
  }
};

console.log(values);
console.log(roles);

The app code:

<div>
   <div className="mb-2 pb-1 border-b text-sm">
      Choose user roles:
   </div>
<ul className="flex items-center gap-1">
{checkBoxInputs.map((role, index) => (
  <li key={index}>
    <input
      type="checkbox"
      id={role.value}
      name="roles"
      value={role.value}
      checked={isChecked}
      onChange={handleCheckboxChange}
    />
    <label htmlFor={role.value} className="text-sm ml-1">
      {role.label}
    </label>
  </li>
  ))}
</ul>
</div>

Though the current implementation either checks or unchecks all inputs together.

Also, the values don't get removed from roles array when the checkboxes are checked out.

Update:

Sharing what worked for me:

const [roles, setRoles] = useState([]);

const handleCheckboxChange = (e) => {
    if (e.target.checked) {
      if (!roles.includes(e.target.value)) {
        setRoles([...roles, e.target.value]);
      }
    } else {
      var filteredRoles = roles.filter(function (value, index, arr) {
        return value !== e.target.value;
      });
      setRoles(filteredRoles);
    }
  };

And the jsx code which worked:

<div>
    <div className="mb-2 pb-1 border-b text-sm">
       Choose user roles:
    </div>
    <ul className="flex items-center gap-1">
    {checkBoxInputs.map((role, index) => (
         <li key={index}>
            <input
                type="checkbox"
                id={role.value}
                name="roles"
                value={role.value}
                onChange={handleCheckboxChange}
            />
            <label htmlFor={role.value} className="text-sm ml-1">
                 {role.label}
            </label>
         </li>
         ))}
     </ul>
  </div>

Note: I have been using tailwind css for the UI part in above code



Solution 1:[1]

you should check in checked prop that checked value is equal to role.value.And also you should push data either using push() or spread operator.

const [roles, setRoles] = useState([]);

  const checkBoxInputs = [
    {
      id: 1,
      label: "Admin",
      value: "admin"
    },
    {
      id: 2,
      label: "Seller",
      value: "seller"
    },
    {
      id: 3,
      label: "User",
      value: "user"
    }
  ];

  const [CheckedValue, setCheckedValue] = useState();

  const handleCheckboxChange = (e) => {
    if (e.target.checked) {
      setCheckedValue(e.target.value);
      if (!roles.includes(e.target.value)) {
        setRoles([...roles, e.target.value]);
      }
    }
  };

then in return statement

return (
    <div>
      <div className="mb-2 pb-1 border-b text-sm">Choose user roles:</div>
      <ul className="flex items-center gap-1">
        {checkBoxInputs.map((role, index) => (
          <li key={index}>
            <input
              type="checkbox"
              id={role.value}
              name="roles"
              value={role.value}
              checked={role.value === CheckedValue}
              onChange={handleCheckboxChange}
            />
            <label htmlFor={role.value} className="text-sm ml-1">
              {role.label}
            </label>
          </li>
        ))}
      </ul>
    </div>
  );

Sources

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

Source: Stack Overflow

Solution Source
Solution 1 Arik Patel