I have an app where i use a select tag to add values in a table. With this select i can select just one value and to add it in the table.
Some of the code of select input:
const searchPlayer = selectedItems => {
selectedItems = selectedItems.map(name => name.toLowerCase());
let arrayOfMatchedObjects = team.filter(object => {
return selectedItems.some(selectedItem =>
JSON.stringify(object)
.toString()
.toLowerCase()
.includes(selectedItem)
);
});
return arrayOfMatchedObjects;
};
The issue is that it doesn't work properly, because when i select a name but don't save it, and after that i change my mind and i select another name, in the table will be added both names, but i can't understand why, because in this way i add 2 names just clicking once on the button. Who knows how to solve this? link to app: https://codesandbox.io/s/serene-hamilton-go4m3
From your current code, you concate the selection in useEffect(), which causes the multi-selected items to been passed to the table.
Remove the concate method would fit your demand.
Update
Replace this
const addPlayer = () => {
setnewPlayer(searchPlayer(savedPlayer));
};
useEffect(() => {
setSavedPlayer(
Array.from(new Set(savedPlayer.concat(selectedItems)).values())
);
}, [selectedItems]);
to
const addPlayer = () => {
const data = Array.from(new Set(savedPlayer.concat(selectedItems)).values());
setnewPlayer(searchPlayer(data));
setSavedPlayer(data);
};
Related
I have created a dynamic form which can have rows added and removed and are stored in a state array.
I need to remove the index passed into the function from the array, without storing a null or empty value.
This is my current code for removing the rows however this simply removes the last row and not the one required at index
const removeRow = (index) => {
setLocationRows((current) =>
current.filter((employee, i) => {
return index !== i;
})
);
};
This code removes the required index however sets the value to null / empty which messes up when after removing and adding rows.
setLocationsObj((current) => {
const copy = { ...current };
delete copy[index];
return copy;
});
Joe.
Im supposing you have something like this:
const [locationRows, setLocationRows] = useState([]);
const removeRow = (index) => {
setLocationRows(locationRows.filter((e,i)=> i !== index))
};
If so, try the above code.
For the complete CRUD operation you can use the following:
const addRow = (newRow) => {
setLocationRows([... locationRows, newRow])
};
const updateRow = (rowData) => {
setLocationRows(locationRows.map(e => {
if(e.id === rowData.id) return rowData;
else return e;
});
};
I hope this can help you!
I recently had to do something very similar and used the array splice method, as it allows you to remove the element at a specific index.
const removeRow = (index) => {
setLocationRows((rows) =>
// create deep copy
const newRows = JSON.parse(JSON.stringfy(rows));
// remove 1 element at index
newRows.splice(index, 1);
return newRows;
);
};
If you are dealing with any sort of nested array it's important to create a deep copy of that array, as the const copy = [...rows] method only creates a shallow copy and can cause all sorts of bugs when trying to manipulate the data further.
Hope this helps!
i have this code https://stackblitz.com/edit/react-wc2ons?file=src%2FSection.js
I have sections, and i can add items to those sections. How can i delete some item? I tried
const removeItem = (i) => {
setSections((section) => {
const itemTarget = section.items[i];
const filtered = section.items.filter((item) => item !== itemTarget);
return {
...section,
items: filtered,
};
});
};
But for some reason it doesn't work
The removeItem callback prop you pass into the Section component is the way to go and you should get rid of passing setSections down to it as well.
removeItem={(i) => removeItem(index, i)}
Child components shouldn't do parent's work so you had it right at first, I'm going to help you implement that since I can already see the removeItem handler being there in the App component.
removeItem has already all the info you need, I'm going to rename the arguments so it's more clear.
const removeItem = (sectionIndex, index) => {
const newSections = sections.slice();
const newItems = newSections[sectionIndex].items.slice();
newItems.splice(index, 1);
newSections[sectionIndex].items = newItems;
setSections(newSections);
};
Then get rid of removeItem implementation in the Section component and destructure it from the props.
You are using setSections, but you return a single section instead of an array of sections. You probably need something like this:
// using the `section` variable from the upper scope
const removeItem = (i) => {
setSections((sections) => {
const itemTarget = section.items[i];
const filtered = section.items.filter((item) => item !== itemTarget);
const newSections = [...sections];
newSections[section.id] = {
...section,
items: filtered,
};
return newSections;
});
};
A few tips (you don't have to follow them): TypeScript can prevent such mistakes and give useful error messages. Immer.js can make writing such code simpler.
Your problem is that section is an array. So you are currently accessing the undefined property items on it. You would have to change your function to something like this
const removeItem = (i) => {
setSections((section) /* aqui vc tinha chamado de prev*/ => {
const itemTarget = section[i].items[j];
const filtered = section[i].items.filter((item) => item !== itemTarget);
return [...section, {
...section[i],
items: filtered,
}]
});
};
where i is the section in question and j is the item you want to delete.
here is a crude solution to your problem (i noticed other bugs in the code but this solves your issue with removing items at least), but i would separate the sections and items into separate components that in turn has its own states.
There you can add/remove items withing its parent section much more easily.
Now we have to work around this by looking for which section the code wants to remove the current item in.
https://stackblitz.com/edit/react-xxbvp1?file=src%2FSection.js
I am trying to change the state by selecting and deselecting the language option in the code below. So far I can update the state by adding a language, my problem is that, if I click on the same language again, I will add it another time to the array. Can anyone explain me how to add or remove the language from the array when clicked one more time?
export default function Dashboard(props) {
const [language, setLanguage] = useState('');
const handleLanguageChange = changeEvent => {
changeEvent.persist()
setLanguage(prevState => [...prevState, changeEvent.target.value])
};
}
It looks like your only issue is your logic in the place where you are handling update. Usage of hooks is correct
So first of all you need to set proper initial value. As you plan to store your languages in an array.
Second part is updating the array. So you can either find clicked language in the array and if it is exist - then use filter to set your new value or filter and compare length of existing array and new one.
const [language, setLanguage] = useState([]);
const handleLanguageChange = changeEvent => {
changeEvent.persist()
setLanguage(prevState => {
const lang = changeEvent.target.value;
if (prevState.includes(lang) {
return prevState.filter(el => el !== lang);
}
return [...prevState, lang]
})
};
You will need a good old check.
if (!languages.includes(changeEvent.target.value) {
// code to add the language
}
Check the selected value using find() method on language array if it returns undefined, then push into array. Rename the state variable as languages otherwise it's confusing (Naming convention standard).
const [languages, setLanguages] = useState('');
const handleLanguageChange = changeEvent => {
changeEvent.persist()
if (!languages.find(value => value == changeEvent.target.value)) {
setLanguages(prevState => [...prevState, changeEvent.target.value])
}
};
2 Things here
Instead of having
<option value="Deutsch">Deutsch</option>
<option value="Englisch">Englisch</option>
use an languages array of json so it bacomes easy for you to add them like
languages= [{value='Deutsch',name= 'Deutsch',...}]
2.setLanguage sa a direct value
setLanguage(changeEvent.target.value)
I am currently working on an online store that filters products based on certain criteria such as size, stock, gender, etc.
While I have been able to make it work to a certain extent. My program currently filters by size, gender, sorts by price etc. However, I cannot get it to filter by brand. For some reason once I click on the brand, I am able to filter the function once, however, once I click on another brand the filter for that particular brand does not run.
Here is the link to the code sandbox:
https://codesandbox.io/s/mystifying-roentgen-7mp0t
I am currently stuck with filtering by brand and I have tried to compared my filtered result to the state of the item clicked, by checking if the brand is included in the item and by using localeCompare().
Here is the link to the code sandbox:
https://codesandbox.io/s/mystifying-roentgen-7mp0t
createCheckboxes = () => available_sizes.map(this.createCheckbox);
handleFormSubmit = event => {
//4) this button updates the filters on the sizes, which I think I need to fix to update the brands, the price and the gender
event.preventDefault();
//5) right here I am storing the selected checkboxes which is what I was doing before by pushing the checkboxes
const selectedSizes = [...this.selectedCheckboxes];
const shallowCopy = [...this.state.filteredProducts];
let filteredProducts = shallowCopy.filter(product =>
selectedSizes.every(size =>
product.stock.some(s => s.stock > 0 && s.size === size)
)
);
let filteredGender = filteredProducts.filter(product => {
return product.gender.some((item, idx, arr) => {
return item[this.selectedGender] === false ? null : product;
});
});
//***this is the function that is not currently running***//
let filteredData = filteredGender.filter(product => {
//console.log(product.brand.includes(this.state.activeBrand))
//console.log(product.brand = this.state.brand)
return product.brand.includes(this.state.activeBrand)
});
let sortedPrice = filteredData.sort((a, b) => {
return this.state.sortBy === "min"
? a.price - b.price
: b.price - a.price;
});
this.setState({
filteredProducts: sortedPrice
});
};
I am expecting to be able to filter by brand wit this function, once an item is clicked.
Here is the link to the code sandbox:
https://codesandbox.io/s/mystifying-roentgen-7mp0t
There are 2 errors in your application:
1) the first one is reported by #user753642 in comment to your question, remove this line from index.js, because it sets your brand of all products to "":
console.log(product.brand = this.state.brand)
2) you are filtering filteredProducts and no the all products. While after first filtering on brand the filterdProducts does not have any item of other brands, it returns an empty collection after filtering on another brand. Change line in handleFormSubmit in index.js, from:
const shallowCopy = [...this.state.filteredProducts];
to:
const shallowCopy = [...this.state.products];
I am creating a questionnaire type form using ReactJs and Ant Design. It is a follow up question of How to create a questionnaire type form using Ant Design?
Now I am succeeded in adding new questions and their respective answers but not in removing them. Let's suppose I have added three questions and when I am trying to remove any one of them, its always removing the last one. The related code for removing is as follows:
remove = k => {
console.log(k);
const { form } = this.props;
// can use data-binding to get
const keys = form.getFieldValue("keys");
// We need at least one passenger
if (keys.length === 1) {
return;
}
keys.splice(k, 1);
// can use data-binding to set
form.setFieldsValue({
keys: keys
});
console.log(keys);
};
The complete code can be found as a demo on codesandbox.io.
I have done something similar in the past. Got rid of the boilerplate of antd's remove and replaced with this. Every time I add a row I push that row (object) to formRows array then removing like this:
remove = key => {
const newRows = this.state.formRows.filter(r => r.key !== key)
this.setState(
prev => ({
formRows: newRows
})
)
}