Two Checkboxes(or more), One Form

John J Wisneski
4 min readMar 26, 2021

--

This was in the creative commons search for checkboxes, *shrug* “File:Farm-Fresh check box list.png” by FatCow is licensed under CC BY 3.0

I was making something in React that had a controlled form that involved a text field, a drop-down, and some checkboxes. The documentation:

Is pretty good and thorough for most things and has a bit of information in the multiple-inputs part of the article, but didn’t really go into accepting information from multiple checkboxes, and there also isn’t as much information on setting the initial value of multiple checkboxes and then clearing out that information (which is essentially just the reverse of the prefill).

Here is The React docs for a controlled checkbox:

class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
};

this.handleInputChange = this.handleInputChange.bind(this);
}

handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value });
}

render() {
return (
<form>
<label>
Is going:
<input
name="isGoing" type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
</label>
<br />
<label>
Number of guests:
<input
name="numberOfGuests" type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</label>
</form>
);
}
}

So here is my solution for an edit form, or something where you need to prepopulate a checkbox. There is probably a better method out there, but I could not find it. So if you are in dire straits (Hi, Mr. Knopfler), use the below make it better and continue on your way.

Our object that we are going to edit is coming in from the database with a key of ‘whatever’ and the value as a CSV (comma-separated value). We can set the initial object as suggested in the React documentation:

object = {whatever: "Thing,Thing 2,Thing 3"}
setFromData({
whatever: object.whatever})

We are going to run an additional function to check the boxes, but I’ll get to that in a bit.

My checkboxes are somewhat hardcoded into the form; I have an array then I map through it to make each of the inputs. If you wanted it to be dynamic, just have the array get fetched from ‘wherever’ then map over that. In my form the checkbox creation will look like below:

const whatevers = ["Thing,Thing 2,Thing 3,Thing 4,Thing 5"]const whateverInputs = whatevers.map((whatever, i)=>{return(<label key={i}>{whatever}<inputtype="checkbox"name="whatever"onChange={handleCheck}value={whatever}/></label>)})

Straightforward. The name will be the same for all of them and the value is going to be the return of the map function.

Let us go to the handle. Check function now — you can have this in the general handle change function that the rest of the form is in, and follow the React docs suggestion for the value ternary and just set it up so that if it is checked, it will be the checkedArr. I just isolated handleCheck to focus on it more easily:

function handleCheck(event){const checkedArr = [];const name = event.target.name;if (event.target.checked){const checkeds = document.getElementsByTagName('input');for (let i = 0; i < checkeds.length; i++) {if (checkeds[i].checked) {checkedArr.push(checkeds[i].value);}}}setFormData({...formData,[name]: checkedArr,});}

So we check to see if the target is checked (when you check something it’s basically a boolean switch: checked is true and unchecked is false), if it is checkedthen we get all the inputs on the page and put them into an array, we iterate through them all. If it’s checked value is true then we throw it into a new array with all of its other checked friends. We then spread it into the rest of the formData as the array of checked things along with their key of whatever.

So that is how we can send it out as an array. Here is how to populate the checkboxes on the initial and unpopulate the checkboxes if the checkboxes are deleted or something. Here’s inital:

function checkBoxes(run){const boxes = document.getElementsByTagName('input');const whatevers = object.whatever.split(",")for (let i = 0; i < boxes.length; i++) {if (whatevers.find(whatever => whatever === boxes[i].value)) {boxes[i].checked = true;}else{boxes[i].checked = false;}}}

Okay, so we get the inputs again set them into an array. (Side note: this is getting all the inputs so make sure your values from another type of input don’t overlap.) We are then splitting the values. Then for each of the inputs, we are seeing if the value of the checkbox matches something from the split. If they match, that means we want to check that off, otherwise we want it to be unchecked. Then like I said, the method to clear it out is simply the reverse:

const checkeds = document.getElementsByTagName('input');for (let i = 0; i < checkeds.length; i++) {if (checkeds[i].checked) {checkeds[i].checked = false;}}

For this, there’s no need to check it against anything since we just want to uncheck all the checkboxes on the page. If you have other checkboxes on the page maybe change the tag name? I don’t know, I’m not your boss.

But there we have another in my line of blogs considering “I had a very specific problem and here is the solution to that problem that probably no one will ever have as well.” I sure am glad I found that possum, otherwise this is just a wall of text. Scroll back to the top for a nice serotonin hit, and bon voyage on the HMS Coding.

--

--

No responses yet