I have a lot of different checkbox with different array to filled.
here is my checkbox (i have 4 différents)
"required_licence":[]
"equipment":[]
...
<Checkbox
style={styles.checkbox}
value={props.box.cotier}
onValueChange={() => {
props.checked(
"cotier", ** My value to record inside my array **
"required_licence", ** the name of my array **
"box", ** the type of my values (because i also have input) **
props.isChecked ** to change if i'm true or false **
);
}}
color={props.box.cotier ? "#4630EB" : undefined}
/>
Also my fonction to add the value inside my state "form"
const checked = (value, fieldName, type, checked) => {
setBox((oldValue) => {
return {
...oldValue,
[value]: !box[value],
};
});
let values = [value];
if (type === "box") {
if (box[value] === false) {
setArray((oldValue) => [...oldValue, value]);
} else {
let index = array.indexOf(value);
array.splice(index, 1);
}
}
setForm((oldValue) => {
return {
...oldValue,
[fieldName]: [value]
};
});
};
when i click on my checkbox, the value is inside my array but delete the other one so i always have just one value .
My else is supposed to delete when my box is not selected.
Related
Brief example:
piece of state: ['youth', 'college'];
event Object:
{ name: theEvent,
ageDivisions: {
youth: true,
middleSchool: true,
highSchool: true,
college: true
open: false
},
}
What I want to accomplish
I want to filter through multiple event objects and only return when the event at least contains all the matching strings in the state array. this array is created based on what the user selects from the form (image Below)
My approach so far:
So far my approach has been to turn the events age divisions parameter into an array of arrays that contain the key and the value. Positions 1 and 2 respectfully
Here is the code:
codePenLink
if (filterParamaters.ageDivisions !== undefined && filterParamaters.ageDivisions.length != false) {
let parsedEvents = events.data.map(({ attributes: event }) => {
return {
...event,
...event.attributes,
ageDivisions: JSON.parse(event.ageDivisions),
eventStyles: JSON.parse(event.eventStyles),
}
})
console.log({ parsedEvents });
filteredEventss = parsedEvents.filter((event) => {
// make event .attributes.ageDivisions object an array of key value pairs
console.log({ eventThatWeAreFiltering: event });
if ((event.ageDivisions !== undefined && event.ageDivisions !== null)) {
let eventAgeDivisions = Object.entries(event.ageDivisions);
console.log({ theAgifiedObject: eventAgeDivisions });
// This maps through each object in the Object key value pair Array
// It might be easier to use map and just chang the array to only have the matching values
let onlyTrueEventAgedivisions = eventAgeDivisions.map((ageDivision, index) => {
console.log({ theAgeDivision: ageDivision[2] });
if (ageDivision[2] === true) {
return [ageDivision[0], ageDivision[2]];
} else {
return false;
}
})
console.log({ theTrueEventAgedivisions: onlyTrueEventAgedivisions });
}
})
console.log({ theFinishedFilteredevents: filteredEventss });
}
What I did was check if the ageDivisions existed in each object and if it does, run this filterParameters.ageDivisions list, checking if every property that you want to be true is set to true .
const result = parsedEvents.filter((e) => e.ageDivisions && filterParameters.ageDivisions.every(prop => e.ageDivisions[prop]))
console.log(result);
I would like to be able to store some form of dynamic structure in the state.
Each input element calls the same function "handleFormInput".
in "name" the input name is stored.
In "value" the actual value.
After each change these values are stored in the state.
If the user now clicks on the form button, the function "handleForm" is called. This function checks the state and reacts accordingly.
My problem: I check the length of the array, which is always 0.
If I output everything via Console.log, however, I see the elements in the array, also correctly. What have I not considered?
Called on every input change made
handleFormInput(event){
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.state.saveFormData[name] = value;
this.setState({
saveFormData : this.state.saveFormData
}, () => {console.log(this.state.saveFormData)});
}
Called when "Submitting"
handleForm(){
var l = 0;
this.state.saveFormData.forEach(element => {
l++;
});
console.log(l); // output: 0
if(this.state.saveFormData.length == 0){
this.setState({ openNew: false })
console.log(this.state.saveFormData);
}else{
console.log(this.state.saveFormData);
alert('we found Data' + JSON.stringify(this.state.saveFormData));
}
}
Ouput of console.log
Array []
length: 0
ort: "asd"
<prototype>: Array []
Working Example in a Nutshell
if you start with the input, the array is written to the state after each input. Stack Snippet already shows an empty array here. The console in the browser shows an array with one element but with a length of 0.
In the similar answers I find, it always has to do with the fact that the console does not map the exact moment of the array, but only shows a reference, and retrieves the data just in time when it is unfolded.
in my case it seems to behave differently. Since also in the console the array length of 0 is shown
function App() {
return ( < DataEditor / > );
}
class DataEditor extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
def: [],
defRaw: [],
loaded: false,
isLoading: false,
openNew: false,
editFormLoaded: false,
editFormData: [],
saveFormData: []
}
}
handleFormInput(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.state.saveFormData[name] = value;
this.setState({
saveFormData: this.state.saveFormData
});
}
handleForm() {
console.log("The Array Length is propably zero but we can access the element")
console.log(this.state.saveFormData.ort);
console.log("Log the testet Array")
console.log(this.state.saveFormData);
if (this.state.saveFormData.length == 0) {
this.setState({
openNew: false
})
console.log(this.state.saveFormData);
} else {
console.log(this.state.saveFormData);
alert('we found Data' + JSON.stringify(this.state.saveFormData));
}
}
render() {
return ( <
div >
<
input type = "text"
name = "ort"
onChange = {
(e) => this.handleFormInput(e)
}
/> <
button type = "button"
onClick = {
() => this.handleForm()
} > Test State Access and Array < /button> < /
div >
);
}
}
ReactDOM.render( < App / > , document.getElementById("root"));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
This has nothing to do with react, it's simply that on the inside array is still an instance of an object and can have it's properties modified the same way, without actually adding them to the iterable options.
Example here:
const array = [];
array.ort = "test";
console.log(array); // []
console.log(array.length); // 0
console.log(array.ort); // "test"
I suggest using an object instead and iterating over it's values with Object.values or Object.entries.
const object = {};
object.ort = "test";
console.log(object); // {ort: "test"}
console.log(Object.values(object).length); // 1
console.log(object.ort); // "test"
remove an object from an array is not working properly ,but it add object perfectly
const addItem =(selected)=>{
let data = selectedItems ? [...selectedItems] : [];
if (data.length) {
let index = data.indexOf(selected);
console.log(index);
if (index !== -1) {
data.splice(index, 1);
setSelectedItems(data);
} else {
data.push(selected);
}
} else {
data.push(selected);
}
console.log("selected", selectedItems);
setSelectedItems(data);
}
render button function add or remove on click it
<div className="file-list">
<MappedElement
data={[{ _id: 1 }, { _id: 2 }]}
renderElement={(value, index, arr) => {
let check=selectedItems.some((obj) => obj._id === value._id);
console.log("check", check);
return (
<DocumentCard key={index} className={file-list-item ${check ?
"active" : ""}}
onClick={() => addItem(value, arr, index)} /> ); }} />
</div>
For a selectedItems array that looks like:
const selectedItems = [
{ _id: 1, /* other fields */ },
{ _id: 2, /* other fields */ },
{ _id: 3, /* other fields */ },
/* other objects */
];
And a selected object that looks like:
const selected = { _id: 1 };
In order to perform the desired behavior, which is: if the element exists, remove it, else, add it, you can write the following:
// copy selected items with a fail-safe empty array
const data = selectedItems ? [...selectedItems] : [];
// find index of selected element
const removalIndex = data.findIndex(({ _id }) => (_id === selected._id));
// if selected element exists in data array, remove it
if (removalIndex !== -1) {
data.splice(removalIndex, 1);
}
// if selected element doesn't exist in data array, add it
else {
data.push(selected);
}
// update selected elements
setSelectedItems(data);
NOTE: if your array of selected items contains duplicates, meaning multiple objects that contain the same value for _id, then this approach will be removing only the first instance of those. If you want to remove all of them, you'll have to use a loop or recursivity.
Your problem is probably in indexOf method you're using.
You can not use this to find objects in your array.
There are several options you can use. You can use find or findIndex and pass a callback to find an object by the specified (preferably unique property of the object).
Example
let found = data.findIndex(item => item.id === selected.id);
Use
const addItem =(selected)=>{
let data = selectedItems ? [...selectedItems] : [];
if (data.length) {
let index = data.findIndex(value => value._id === selected._id)ж
console.log(index);
if (index !== -1) {
data.splice(index, 1);
} else {
data.push(selected);
}
} else {
data.push(selected);
}
console.log("selected", selectedItems);
setSelectedItems(data);
}
I'm trying to implement a search function that returns find which has search word in the specified array. Let's say, a collection has [aa, ab, aaa], and search word is "a". In this case, return the object to display. Because at least one of the strings in the array has 'a'.
dataStructure
[
{
name:'aa',
searchWords:['aa','ab','bc'] <- I want to use this array for search
},
{
name:'bb',
searchWords:['bb','bc','de'] <- I want to use this array for search
},
...
]
I tried to fix the issue, by using includes(), filter(),indexOf(). However still it returns nothing or returns data when the search word is exactly matched.
How to fix the code to achieve aiming?
Thank you in advance!
this part works well
let filterStudents = students;
if (searchName.length > 0 && searchTag.length === 0) {
filterStudents = students.filter((student) => {
if (
student.firstName.toLowerCase().includes(searchName.toLowerCase())
|| student.lastName.toLowerCase().includes(searchName.toLowerCase())
) {
return true;
}
return false;
});
Problem happens on this part
} else if (searchName.length === 0 && searchTag.length > 0) {
filterStudents = students.filter(
(student) => {
console.log(student.tags);
student.tags.filter((tag) => {
console.log(tag);
tag.indexOf(searchTag) > -1;
});
},
);
} else if (searchName.length > 0 && searchTag.length > 0) {
} else {
console.log('both');
}
You don't return from the filter callbacks
As a sidenote, there is also String#includes:
filterStudents = students.filter(student =>
student.tags.some((tag) => tag.includes(searchTag))
);
If you only want to search for matches when the corresponding searchTag or searchName is filled out, use the conditional operator inside the filter callback to check whether the filter test should be carried out:
const students = [
{
name:'aa',
searchWords:['aa','ab','bc']
},
{
name:'bb',
searchWords:['bb','bc','de']
},
];
const doFilter = () => {
const [searchName, searchTag] = [...document.querySelectorAll('input')]
.map(input => input.value.toLowerCase());
const filtered = students.filter(({ name, searchWords }) => (
(searchName ? name.toLowerCase().includes(searchName) : true) &&
(searchTag ? searchWords.some(word => word.toLowerCase().includes(searchTag)) : true)
));
code.textContent = JSON.stringify(filtered);
};
window.addEventListener('change', doFilter);
<input placeholder="searchName">
<input placeholder="searchTag">
<div>
<code id="code"></code>
</div>
I have many same inputs for percentage purposes, each of them working normally if I'm using normal numbers data. If I'm entering wrong erroneous data like letters or other chars its changing to 0. But it is changing only in screen, data actually catching wrong. For example if I will type 0fsdfsd into input result in screen will be 0 but actual data in input will be 0f.
How to save actual data as0 but not as 0f?
I'm using intl to format data as decimal, and isNaN to catch NaN values.
Input in render()
<input
name="bonusCategory"
value={this.toCurrency(category.bonusrate)}
className="form-control"
style={{ width: "60px" }}
type="text"
onChange={this.inputChanged.bind(this, idx, category.value)}
/>
/>
toCurrency()
toCurrency(number) {
const formatter = new Intl.NumberFormat("ru-RU", {
style: "decimal"
});
let newValue = isNaN(number) ? 0 : number;
return formatter.format(newValue);
}
inputChanged()
inputChanged = (idx, index, e) => {
const { categories } = this.state;
let bonusCategory = e.target.value;
console.log(bonusCategory);
if (bonusCategory.length > 3) return;
categories.forEach(category => {
category.bonusrate =
category.value === index ? e.target.value : category.bonusrate;
});
this.setState(oldState => {
const newDisabledButtons = [...oldState.disabledButtons];
newDisabledButtons[idx] = false;
return {
categories,
isEdit: false,
inCart: true,
disabledButtons: newDisabledButtons
};
});
};
in console.log I can see changing data of bonusCategory and it shows wrong result.
pen: https://codepen.io/fatdrfrog/pen/rNBXwrW
If you want to use some parameters not event for the onChange handler, please try this.
inputChanged = (idx, categoryvalue) => (e) => {
... ... ...
};
You can go ahead and allow the toCurrency to for visual effect but change the input change function as follows
inputChanged = (idx, index, e) => {
const { categories } = this.state;
//check for the value attribute and either set it to zero or to actual value
let bonusCategory = isNaN(e.target.value) ? 0 : e.target.value;
console.log(bonusCategory);
if (bonusCategory > 999) return;
categories.forEach(category => {
category.bonusrate =
category.value === index ? bonusCategory : category.bonusrate; //note the use of bunus category
});
this.setState(oldState => {
const newDisabledButtons = [...oldState.disabledButtons];
newDisabledButtons[idx] = false;
return {
categories,
isEdit: false,
inCart: true,
disabledButtons: newDisabledButtons
};
});
};
You can either use input with type='number' (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input/number) or parse user input before saving it to category.bonusrate (use parseInt or parseFloat depending on your number format):
category.bonusrate = category.value === index ? parseFloat(e.target.value) : category.bonusrate;