Modal popping up at the wrong time due to state - reactjs

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.

Related

How to keep the check box checked , when navigating to other page of react pagination

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.

Checkmark group of checkboxes based on array values

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 : [],

React search and filter: TypeError: setFilterFn is not a function

I'm working on a search and filter function. When I type text into the search box, the content that matches the criteria will be filtered out. I want to use the following function to achieve this, but when I type, the "TypeError: setFilterFn is not a function" will occur.
I don't know where goes wrong, How should I fix it?
Thx a lot!
const [setFilterFn] = useState({ fn: items => { return items; } })
const handleSearch = e => {
let target = e.target;
setFilterFn({
fn: items => {
if (target.value != "")
return items;
else
return items.filter(item => item.fullName.toLowerCase().includes(target.value.toLowerCase()))
}
})
}
The quick fix... add a comma ...
const [,setFilterFn] = useState((items) => ( items));
it also looks as if you may have an issue with your logic..
if (target.value != "")
The operator here should probably be === otherwise you will only filter for blank strings.
Take a look at useState function, that function returning array with two arguments, first value of state , the second is callback function which will change your satate value. You are providing only one value, so react assuming that is value not a function. You can read more in docs

Updating nested useState seems to modify the original data

So I have an implementation of a Text Field input alongside a table in which I'm trying to update the state of staged Data before I submit the data to an API.
In the Dialogs parent component, I have the data defined which I want to show in a table as the original state.
The current problem I'm having is the inputted data is somehow updating the original data's state even though I'm not directly touching this data.
Below is a reproduction of it on Codesandbox, So when you open the link typing into the edit value field should not update the current stock field and I don't see why it is.
CodeSandBox
Here is the callback that modifies the state:
const handleUpdateDip = (value, tank) => {
const newData = stagedData;
const foundIndex = newData.dips.findIndex((d) => d.tank === tank);
if (foundIndex !== -1) {
newData.dips[foundIndex].currentStockValue = Number(value);
setStage({
...stagedData,
dips: newData.dips
});
}
};
So yeah this one seems weird to me and I've been banging my head against the keyboard trying to understand whats going on with it since last night so any help would be appreciated!
You are mutating the current object. Try this
setStage((stage) => {
const foundIndex = stage.dips.findIndex((d) => d.tank === tank);
return {
...stage,
dips: stage.dips.map((d, index) => {
if (foundIndex === index) {
return { ...d, currentStockValue: Number(value) };
}
return d;
})
};
});
Instead of this
const foundIndex = stagedData.dips.findIndex((d) => d.tank === tank);
if (foundIndex !== -1) {
stagedData.dips[foundIndex].currentStockValue = Number(value);
setStage({
...stagedData,
dips: stagedData.dips
});
}
I don't see why it's shouldn't update while the code tells it to do so! This line inside handleUpdateDip():
stagedData.dips[foundIndex].currentStockValue = Number(value);
You shouldn't directly mutate the state. You should make a copy of it first change whatever you want and then set the state to the new value e.g.:
const handleUpdateDip = (value, tank) => {
const foundIndex = stagedData.dips.findIndex((d) => d.tank === tank);
if (foundIndex !== -1) {
const newStagedData = { ...stagedData };
newStagedData.dips[foundIndex].currentStockValue = Number(value);
setStage(newStagedData);
}
};
stagedData.dips[foundIndex].currentStockValue = Number(value); this line updates the value of currentStockValue which is used in the "Current Stock" column.
It seems like the table cell left of the input field simply uses the same state that is changed in handleUpdateDip
<TableCell align="right" padding="none">
{row.currentStockValue}
</TableCell>
<TableCell align="right" padding="none">
<InputTextField
id="new-dip"
type="number"
inputProps={{
min: 0,
style: { textAlign: "right" }
}}
defaultValue={row.currentStockValue}
onChange={(event) =>
handleUpdateDip(event.target.value, row.tank)
}
/>
both are currentStockValue, which handleUpdateDips changes in this line
stagedData.dips[foundIndex].currentStockValue = Number(value);
I think I know what you're thinking. You think that on the one hand, you're updating your state in handleUpdateDip(event.target.value, row.tank) with setStage({...}), so you're only changing your state stagedData.
You value for the "Current Stock", however, is mapped to your data variable and not to stagedData.
So in the end your question is: Why ist data changing when you're only manipulating stagedData.
Of course it happens here: const [stagedData, setStage] = useState(() => data);
(btw you don't need to use a function here, const [stagedData, setStage] = useState(data); is fine). You pass in data by reference here, when your setState hits, the reference will be updated and so will your data.
(another BTW: don't call your state variable settings functions simply setState, this is something used by class components in React. Call them like the state you want to set, e.g. setStagedData).
Now, you can elimate this reference, since you only want the initial values anyways. You could do this by passing a copy, like this: const [stagedData, setStagedData] = useState({...data}); But this still won't work - I not really sure why because I don't know enough about the inner workings of useState, but the reason probably is because it's only a shallow copy instead of a deep copy (you can read more about this here).
But if we do a deep copy and pass this in, it works and your original data will stay untouched. You can deep copy by basically stringifying and then parsing it again (which will not copy any methods the object has, just as a warning).
const copy = JSON.parse(JSON.stringify(data));
const [stagedData, setStagedData] = useState(copy);
And just like that your current stock will stay the same:
I forked your CodeSandBox, so you can see it for yourself.

How to check dynamically rendered checkboxes

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 :)

Resources