Reputation: 693
I'm trying to enable button if both the checkboxes are checked, I have nonworking stackblitz link
I have added the only crux of functionality. Please look into the link for the nonworking demo
import React, { useState } from 'react';
import { render } from 'react-dom';
function App (){
const [checked, toggleCheckbox] = useState({ checkbox1: false, checkbox2: false, disabled: true });
const getDisabled = (state) => {
if (state.checkbox1 || state.checkbox2) {
return false;
} else if (!state.checkbox1 && !state.checkbox2) {
return true;
} else {
return true;
}
};
const handleCheckbox = (checkbox) => {
toggleCheckbox({
...checked,
[checkbox]: !checked[checkbox],
disabled: getDisabled(checked)
});
console.log(checked);
};
const checkDisable = checked.disabled ? 'disabled' : ''
return (
<div>
<div>
<label>
<input
type="checkbox"
className="filled-in"
onChange={() => handleCheckbox('checkbox1')}
checked={checked.checkbox1}
/>
<span className="black-text">Checkbox1</span>
</label>
</div>
<div>
<label>
<input
type="checkbox"
className="filled-in"
onChange={() => handleCheckbox('checkbox2')}
checked={checked.checkbox2}
/>
<span className="black-text">checkbox2</span>
</label>
</div>
<div>
<a className={checkDisable} href="#!">
Next Step
</a>
</div>
</div>
);
}
render(<App />, document.getElementById('root'));
The functionality should be as follows:
Upvotes: 3
Views: 1502
Reputation: 36895
You can simply check the state of both checkbox values.
const isDisabled = !(checked.checkbox1 && checked.checkbox2)
const checkDisable = isDisabled ? 'disabled' : ''
No need to change elsewhere.
Forked stackblitz link. https://stackblitz.com/edit/react-jscqwr?file=index.js
Hey, that worked! I could see in the log that the state one step below the updated state for an instance after clicking in the first checkbox { checkbox1: false, checkbox: false, disabled: false } after clicking the second checkbox the log { checkbox1: true, checkbox: false, disabled: false }
The reason you are seeing outdated state is because the state updator toggleCheckbox
batches the update, thus you'd need to check for the updated status in an effect, which monitors the updated status.
I've updated the stack to track dynamic number of checkboxes.
New fork~ https://stackblitz.com/edit/react-pl1e2n
function App() {
const length = 6;
1️⃣ Generate the initial checkbox states - this prevents un/controlled component error.
const initialCheckboxes = Array
.from({ length }, (_, i) => i + 1)
.reduce((acc, id) => (acc[id] = false, acc), {})
const [checked, toggleCheckbox] = useState(initialCheckboxes);
const [isDisabled, setIsDisabled] = useState(false)
const handleCheckbox = id => {
toggleCheckbox(previous => ({
...previous,
[id]: !previous[id]
}));
};
2️⃣ Update the disable state when the checkbox is selected.
useEffect(() => {
👇 Enable when all checkboxes are not checked - 😅
setIsDisabled(!Object.values(checked).every(_ => !!_))
}, [checked])
3️⃣ Dynamically generate checkboxes
const checkboxElements = Array.from({ length }, (_, i) => i + 1)
.map(id => (
<div key={id}>
<label>
<input
type="checkbox"
className="filled-in"
onChange={() => handleCheckbox(id)}
checked={checked[id]}
/>
<span className="black-text">Checkbox{id}</span>
</label>
</div>
))
return (
<div>
{checkboxElements}
<div>
<a className={isDisabled ? 'disabled' : ''} href="#!">
Next Step
</a>
</div>
</div>
);
}
Upvotes: 4