I'm rendering some checkboxes dynamically, but currently I'm only able to check the first box, and all other boxes operate the first one. How do I get the boxes to work independently of each other?
This is typescript in React. I've tried changing the interface I'm referencing in the function, thinking I was referencing the wrong thing, but none of those worked.
This is the function:
handleCheckboxClick = (entitlement: IApiEntitlements, checked: boolean): void => {
if (checked === true) {
this.selectedEntitlementIDs.push(entitlement.id);
} else {
const index: number = this.selectedEntitlementIDs.indexOf(entitlement.id);
this.selectedEntitlementIDs.splice(index, 1);
}
//tslint:disable-next-line:prefer-const
let entitlementChecked: IEntitlementChecked = this.state.entitlementChecked;
entitlementChecked[entitlement.id] = checked;
let selectAll: boolean = false;
if (this.selectedEntitlementIDs.length === this.state.responses.apiResponses.apiClients.length) {
selectAll = true;
}
this.setState({
entitlementChecked: entitlementChecked,
selectAll: selectAll
});
console.log(this.selectedEntitlementIDs, 'hi');
console.log(entitlementChecked, 'hello');
}
And this is where it's being called:
return (
<Checkbox
checked={this.state.entitlementChecked[entitlement.id]}
data-ci-key={entitlement.id}
id='api-checkbox'
key={entitlement.id}
labelText={entitlement.label}
onChange={this.handleCheckboxClick}>
</Checkbox>
);
I expect each checkbox to be able to be checked, but currently on the first one works, and all others check or uncheck that first one.
You shouldn't keep an array as a property on the class that keeps track of selected items, this isn't tied to the React lifecycle and could potentially not update the view when you want to. Instead you should just use your map (entitlementChecked) you already have to determine if something is checked or not.
handleCheckboxClick(id) {
this.setState(prevState => ({
entitlementChecked: {
...prevState.entitlementChecked,
[id]: !prevState.entitlementChecked[id]
}
}));
}
When calling the handler method, you can just pass the id through that you need specifically.
onChange={this.handleCheckboxClick.bind(null, item.id)}
Here's a rudimentary example for more detail :)
Related
I want to ask , how to keep save the id's of the check boxes in a state , and whenever i switched back to first page it automatically search the element with id and mark check boxes automatically.
and if i unmark the checkbox , it deletes the id from the state.
i am able to think about the logic , but cant able to code,it
Small help ,will leads to solve this problem
While switching to other pages, i am succesfully saving the data ,by updating the state
`
// push all the unique objects (combination of previous state of selectedPayments and data from list)
setSelectedPayments((prevState) => {
var arr = [...prevState, ...list];
var newState = [
...new Map(arr.map((item) => [item.id, item])).values(),
];
return newState;
});
console.log('Selected payments are', selectedPayments);
`
Also , removing the objects , if again the checkbox is unchecked ,and updating the state
`
// pull all the objects , which got unChecked
setSelectedPayments((prevState) => {
var newState = prevState.filter(function (objFromA) {
return !list.find(function (objFromB) {
return objFromA.id === objFromB.id;
});
});
return newState;
});
`
Only facing issue with keeping track of the checked boxes, i have implimented this, this is keeping track of main(parent checkbox).
How to extract the ids saved and check the checkboxes when we naviagete from one page to another
`
let elementId = e.target.id;
if (selectedBoxes.includes(elementId)) {
const newArray = selectedBoxes.filter((e) => e !== elementId);
setSelectedBoxes(newArray);
} else {
setSelectedBoxes((prevState) => {
return [...prevState, elementId];
});
}
`
First i modified the Res Json , so that it set's a property isSelected = true,
by comparing the element from the selectedPayments
inAll check handler , i set the selectedPayments like this
And render using this
This is how ,i solved this problem.
** Better and improved answers are always welcome, please share your views.
Forgive me there are a lot of questions asking this same thing but from over 10+ years ago.
Is there any way to checkmark a group of checkboxes based on an array in React? I have an array saved within state (stepThree) that I need to pulldown when a user returns to this screen within a multistep form. I'm looking for a way that the values within that array become/stay checked upon return to that screen so it shows the user their previous selections.
Current set-up explained below
State is opened with empty checkedBox array and stepThree initialized to pull responses later. checkedBox is eventually cloned into stepThree.
this.state = {
checkedBox: [],
stepThree: this.props.getStore().stepThree,
};
Boxes that are checked by the user are added to checkedBox array or removed if unchecked.
handleCheckboxChange = (event) =>{
const isChecked = event.target.value; //Grab the value of the clicked checkbox
if (this.state.checkedBox.includes(isChecked)) {
// If the checked value already exists in the array remove it
} else {
// If it does not exist, add it
}
}
Validate and store the completed array on clicking next
if (Object.keys(validateNewInput).every((k) => { return validateNewInput[k] === true })) {
if (this.props.getStore().stepThreeObjects != this.state.checkedBox) { // only update store of something changed
this.props.updateStore({
// Store the values of checkedBox inside stepThree and run updateStore to save the responses
});
} else {
// Return an error
}
Sample checkbox
<label className="choice-contain">
<span>Checkbox Sample</span>
<input
value="Checkbox Sample"
name="Question 3"
type="checkbox"
onChange={this.handleCheckboxChange}
/>
</label>
I've tried to create a persistCheckmark function that pulls the values of the array from stepThree and then does a comparison returning true/false like I do in the handler but since this is not an event I can't figure out how to trigger that function on return to the step.
Currently when returning to the step nothing is checked again and I believe that has to do with checkedBox being initiated as empty.
persistCheckmark(event) {
const isChecked = event.target.value; //Grab the value of the clicked checkbox
if (this.state.stepThree.includes(isChecked)) {
return true;
} else {
return false
}
}
Figured it out thanks to an old post here: How do I set a group of checkboxes using values?
Just updated the filter for when the component mounts
componentDidMount() {
if (this.state.stepThree != undefined) {
var isChecked = this.state.stepThree
$('input[type="checkbox"]').filter(function() {
return $.inArray(this.value, isChecked) != -1;
}).prop('checked', true);
} else { return }
}
and then added a ternary in the state initiation to check the storage and copy it over so it doesn't initialize as empty every time.
checkedBox: this.props.getStore().stepThree != undefined ? this.props.getStore().stepThree : [],
So I have two modals that I am using one of them was already implemented and behaves as expected however when I've added the other modal depending on the condition of if there is any true value when mapping over the array the way it works right now both modals show when there is a true value. I think this is because there are multiple false values returned from my .includes() function before the true appears. I think a good solution for this would be to make an array of all the values returned when I run .includes() on the entries then I can check that array for any true values but I cant seem to get the values into an array. When I try and push them into an array they just all push into their own separate arrays. This may be the wrong approach if it is can you explain what a better approach would be:
const checkPending = () => {
if(entries){
entries.map(descriptions => {
const desc = descriptions.description
//check if there are any pending tests
const check = desc.includes("pending")
//if the check returns true show the pending modal if it doesnt set the other modal to true
if(check === true){
setShowModal(false)
setShowPendingM(true)
}else{
setShowModal(true)
}
})
}
}
return(
<Button
onClick={() => checkPending()}
className={`${styles.headerButton} mr-2`}
>
Add File
<Plus />
</Button>
)
setShowModal & setShowPendingM are both passed from a parent component as props. They are both initialized as false. The most straightforward question I can pose is is there any way to say if there are any true values returned from .includes then do something even if there are false values present
I think this is how your checkingPending method should look like.
const checkPending = () => {
if(entries){
let pending = false;
entries.forEach((descriptions) => {
const desc = descriptions.description
if(desc.includes('pending')){
pending = true;
}
});
if(pending) {
setShowModal(false);
setShowPendingM(true);
} else {
setShowModal(true);
setShowPendingM(false);
}
}
}
Let me know if you have any additional questions.
I'm wondering, if there's a way to ask for confirmation with Reakit's checkbox. I'm using Reakit, since I found a quick way to get it to read database's boolean information, but I welcome other methods too!
I'm used to doing confirmations with buttons with async and window.confirm:
<button onClick={async hiStackOverflow => {
if (window.confirm("Want to do this?")) {
// saving to database here
}
}}>
But I didn't figure out how to do it with a checkbox. In short, I want for the page to confirm (and then save to database), when the user toggles on/off the checkbox.
// personData = database table, with boolean "recurring"
// row = which entity in a table we are talking about
function CheckboxThing ({ row, personData }) {
const checkbox = useCheckboxState({state: personData[row].recurring});
return (
<div className="checkbox-admin-other">
<Checkbox
{...checkbox}
// what here?? onClick or something?
/>
</div>
);
}
Reakit's checkbox can be used like this:
const toggle = () => setChecked(!checked);
return <Checkbox checked={checked} onChange={toggle} />;
This means that the checkbox will be checked if the variable 'checked', which needs to be put in the state of your React component, is true and that the method called 'toggle' will be called when the user toggles the checkbox. In that method, you can put the code which will show the Confirmation Prompt and then change checked if user clicked 'Yes' or leave it as it is if they check 'No'.
You can "observe" changes on checkbox.state using React Hooks:
function CheckboxThing({ row, personData }) {
const checkbox = useCheckboxState({ state: personData[row].recurring });
React.useEffect(() => {
// checking if state has changed
if (checkbox.state !== personData[row].recurring) {
if (window.confirm("Want to do this?")) {
// saving to database here
} else {
// revert checkbox state otherwise
checkbox.setState(!checkbox.state);
}
}
}, [checkbox.state, checkbox.setState, personData[row].recurring]);
return (
<div className="checkbox-admin-other">
<Checkbox {...checkbox} />
</div>
);
}
With React.useEffect, the user will see the checkbox checked before window.confirm opens. But you can use React.useLayoutEffect instead if you want it to open before checkbox state changes on the UI.
After coding around a little while, I found the solution! It turns out, you can put async inside Reakit Checkbox. Thanks to Tomislav and Diego, their answers helped me try different things and get it clean!
Here's the full function:
// admin can edit the right to join back to the queue after getting to the front
function RecurringBox ({ row, personData }) {
// sets the original values
const checkbox = useCheckboxState({state: personData[row - 1].recurring});
return (
<Checkbox {...checkbox} onChange={async checkboxSwitch => {
if (window.confirm("Change it?")) {
checkboxSwitch.persist();
// saving it to the database
await put(`${process.env.API_PATH}/person`,
{
"id": personData[row - 1].id,
"name": personData[row - 1].name,
"recurring": checkboxSwitch.target.checked
});
reload(`${process.env.API_PATH}/person`);
} else {
return null;
}
}}/>
);
}
My users complain that they can enter new value (one that is not included in the options) even when that is not exactly the case.
When you input text, without selecting item from options and then leave the typeahead, the text stays there, which leads users to believe that new value (one that is not included in options) can be entered.
What would be the right way to deal with this?
I am quite new to frontend development, so the answer might actually be obvious.
One way to address this is to clear the typeahead when the user blurs the input unless they've made a valid selection. Here's an example:
https://codepen.io/anon/pen/qLBaYK
class BlurryTypeahead extends React.Component {
state = {
selected: [],
};
render() {
return (
<Typeahead
onBlur={this._handleBlur}
onChange={this._handleChange}
options={['one', 'two', 'three']}
ref={typeahead => this._typeahead = typeahead}
selected={this.state.selected}
/>
);
}
_handleBlur = () => {
// Check if there are selections.
if (!this.state.selected.length) {
// Clear the component if not.
this._typeahead.getInstance().clear();
}
}
_handleChange = (selected) => {
// Track the selected state
this.setState({ selected });
}
}