I'm a beginner in Next Js. and I'm trying to implement select all on the checkboxes.
I following this reference https://www.freecodecamp.org/news/how-to-work-with-multiple-checkboxes-in-react/
what I expect is, if the checkbox select all is checked then sum all the prices.
but I don't know how to start it.
Here is my sandbox https://codesandbox.io/s/eager-feather-2ieme9
Any help with this would be greatly appreciated, been working on this for a while and exhausted all avenues!
CodePudding user response:
You can check the below logic with some explanation
You also can check this sandbox for the test
import { useState } from "react";
import { toppings } from "./utils/toppings";
// import InputTopings from "./InputTopings";
const getFormattedPrice = (price) => `$${price.toFixed(2)}`;
export default function TopingApp() {
const [checkedState, setCheckedState] = useState(
new Array(toppings.length).fill(false)
);
// console.log(checkedState);
const [total, setTotal] = useState(0);
//Separate `updateTotal` logic for avoiding duplication
const updateTotal = (checkboxValues) => {
const totalPrice = checkboxValues.reduce((sum, currentState, index) => {
if (currentState === true) {
return sum toppings[index].price;
}
return sum;
}, 0);
setTotal(totalPrice);
};
const handleOnChange = (position) => {
const updatedCheckedState = checkedState.map((item, index) =>
index === position ? !item : item
);
setCheckedState(updatedCheckedState);
//update total
updateTotal(updatedCheckedState);
};
const handleSelectAll = (event) => {
//filled all checkboxes' states with `Check All` value
const updatedCheckedState = new Array(toppings.length).fill(
event.target.checked
);
setCheckedState(updatedCheckedState);
//update total
updateTotal(updatedCheckedState);
};
return (
<div className="App">
<h3>Select Toppings</h3>
<div className="call">
<input
type="checkbox"
name="checkall"
checked={checkedState.every((value) => value)}
onChange={handleSelectAll}
/>
<label htmlFor="checkall">Check All</label>
</div>
<ul className="toppings-list">
{toppings.map(({ name, price }, index) => {
return (
<li key={index}>
<div className="toppings-list-item">
<div className="left-section">
<input
type="checkbox"
// id={`custom-checkbox-${index}`}
name={name}
value={name}
checked={checkedState[index]}
onChange={() => handleOnChange(index)}
/>
<label>{name}</label>
</div>
<div className="right-section">{getFormattedPrice(price)}</div>
</div>
</li>
);
})}
<li>
<div className="toppings-list-item">
<div className="left-section">Total:</div>
<div className="right-section">{getFormattedPrice(total)}</div>
</div>
</li>
</ul>
</div>
);
}
CodePudding user response:
You can lift the 'Check all' state to a parent object and on change of this state set all <input/>
tags value to that state you can achieve this by dividing your app. First create a component for the items in the list like <Toppings/>
and give props to this component like so <Toppings name={name} price={price} checkAll={checkAll}/>
inside the toppings component create a state variable like this
const Toppings = ({name,price, checkAll}) => {
const [checked,setChecked] = useState(checkAll)
return (
<li key={index}>
<div className="toppings-list-item">
<div className="left-section">
<input
type="checkbox"
// id={`custom-checkbox-${index}`}
name={name}
value={checked}
onChange={setChecked(!checked)}
/>
<label>{name}</label>
</div>
</div>
</li>
)
}
Edit:
inside index.js:
const [checkAll, setCheckAll] = useState(false)
//when rendering inside return method
{toppings.map(({name,price},index) => <Toppings key={index} name={name} price={price} checkAll={checkAll}/> )