Reputation: 211
I have to create a button that activates when a check box is checked and disables when unchecked. I was able to achieve this by the following code.
import React from "react";
import "./styles.css";
import{useState} from 'react'
export default function App() {
const [change, setChange] = useState(true);
function buttonHandler(){
setChange(!change)
}
return (
<div className="App">
<button disabled={change}>Click Me</button>
<input type="checkbox" onChange={buttonHandler}/>
<input type="checkbox" onChange={buttonHandler}/>
<input type="checkbox" onChange={buttonHandler}/>
</div>
);
}
Now I have another challenge where I have to keep it disabled if more than 1 check box is checked. I tried to use object and array manipulation but it does not work. Any advice on how this can be achieved.
Upvotes: 0
Views: 4085
Reputation: 63550
Wrap your input elements in a parent element like form
or div
.
Maintain state; an array that contains each box status (either true
or false
). When a box is changed call the handleChange
which will update the state.
The button disabled property should call a function called isDisabled
which will check to see if there are zero boxes checked or more than one box checked, returning true if the condition is matched.
const { useEffect, useState } = React;
function Example() {
const [boxes, setBoxes] = useState([]);
// In the text I suggested wrapping the inputs in
// a parent element. This was so we could use the following
// code to find its index within the list of inputs
// without adding any more code to the JSX
// Cribbed from https://stackoverflow.com/a/39395069/1377002
function handleChange(e) {
// Destructure the children from the parent of
// the element that was changed (ie all the input elements)
const { parentNode: { children } } = e.target;
// Find the index of the box that was changed
const index = [...children].indexOf(e.target);
// Copy the state
const newState = [...boxes];
// Toggle the boolean at the index of
// the `newState` array
newState[index] = !newState[index];
// Set the state with the updated array
setBoxes(newState);
}
// `filter` the boxes that return true.
// Return true if the length is 0 or > 1.
function isDisabled() {
const len = boxes.filter(box => box).length;
return len === 0 || len > 1;
}
return (
<div className="App">
<button disabled={isDisabled()}>Click Me</button>
<form>
<input type="checkbox" onChange={handleChange}/>
<input type="checkbox" onChange={handleChange}/>
<input type="checkbox" onChange={handleChange}/>
</form>
</div>
);
}
ReactDOM.render(
<Example />,
document.getElementById('react')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Additional documentation
Upvotes: 0
Reputation: 4333
import React from "react";
import{useState} from 'react'
export default function App() {
const [checkboxStatus, setCheckboxStatus] = useState(Array(3).fill(false));
function buttonHandler(index){
let status = [...checkboxStatus];
status[index] = !status[index]
setCheckboxStatus(status)
}
return (
<div className="App">
<button disabled={checkboxStatus.filter(status => status === true).length != 1}>Click Me</button>
{Array(3).fill(0).map((_, index) => <input type="checkbox" checked={checkboxStatus[index]} onChange={() => buttonHandler(index)}/>)}
</div>
);
}
You can do that by keeping track of the status of the checkbox rather than tracking the status of the button. This is because if you know the status of all the checkboxes, you can easily calculate the status of the button.
I have also taken the liberty of converting the checkbox to map it since the content is the same. You can do the same by passing the index to each of them. Something like <input type="checkbox" onChange={() => buttonHandler(0}/>
and so on for each of the inputs.
Upvotes: 2