I am trying to add and delete an obect from an array, I have been able to figure out the add object part, but the deletion is not working. I have used filter() but it did nothing. Now I am using splice, it works but it deletes the first element, instead of the selected item. below is a sample code, and I have shown only the functions for better clarity.
handleDelete(item) {
this.setState(({ list}) => {
const newList = [...list];
newList.splice(item.key, 1);
console.log('deleted', newList);
return { list: newList };
});
}
handleAdd() {
const { firstname, lastname, email, phone} = this.state;
const ID = uuid();
const newItemObject = {
key: ID,
firstname: firstname,
lastname: lastname,
email: email,
phone: phone,
image: null,
};
this.setState(prevState => ({
list: [...prevState.list, newItemObject]
}));
}
I would like to
The item's key and index in the array are probably not the same. If the item is in the array, you can use Array.indexOf() to find it's index, and splice it out:
handleDelete(item) {
this.setState(({ list }) => {
const newList = [...list];
const index = newList.indexOf(item);
newList.splice(index, 1);
return {
list: newList
};
});
}
Or if you want to use Array.filter(), check if the key of of current element (o) is different from that of item:
handleDelete(item) {
this.setState(({ list }) => ({
list: list.filter(o => o.key !== item.key)
}))
}
Related
working on a React/Firestore app, trying to get the Id-s back into the objects array.
Here is the code:
function getEm() {
setLoading(true);
ref.onSnapshot((querySnapshot) => {
const items = [];
const ids = [];
querySnapshot.forEach((doc) => {
items.push(doc.data());
ids.push(doc.id);
});
//unzipped
setItems(items);
setIds(ids);
console.log(ids);
console.log(items);
//zipped
const item = _.zipObject([(ids = [])], [(items = [])]);
setItems(item);
setLoading(false);
});
}
Any idea on what is wrong with the '_zipObject' line?
You could just add the id to the data object as soon as you get it from the query snapshot:
querySnapshot.forEach((doc) => {
const newItem = {
...doc.data(),
id: doc.id
}
items.push(newItem);
});
This would give you an array of object with all the data from the object + the id
The function below receiving a rating value inside an object. While ID or Question stay intact, the rating value can be updated. As a result a React state value should be updated.
Is there a way to make this function look prettier/concise while just using a vanilla javascript.
ratingCompleted = ({ rating, question, id }) => {
let array = this.state.ratingResponses;
const index = array.findIndex(elem => elem.id == id);
if (index === -1) {
array.push({ rating, question, id });
this.setState({ ratingResponses: array });
} else {
array.map(object => {
if (object.id === id) {
object.rating = rating;
return object;
} else {
return object;
}
});
this.setState({ ratingResponses: array });
}
};
Make sure you spread to stop mutations
This could be a little cleaner but i thought I would show each step.
const array = [...this.state.ratingResponses]; // spread this so as to make a copy
let updatedArray;
const hasRatingAlready = array.some(item => item.id === id);
if (!hasRatingAlready) {
updatedArray = [...array, { rating, question, id }];
} else {
updatedArray = array.map(item => item.id === id ? {...item, rating} : item);
}
this.setState({ ratingResponses: updatedArray });
I want to store an array state using async storage. but everytime i reload the app, it comes up blank. below is a sample code, and I have shown only the functions for better clarity.
componentDidMount() {
this.getDataSync();
}
getDataSync = async () => {
try {
const list = await AsyncStorage.getItem(LIST_STORAGE_KEY);
const parsedList = JSON.parse(list);
const obj = Object.keys(parsedList);
this.setState({ isDataReady: true, list: obj || [] });
} catch (e) {
Alert.alert('Failed to load list.');
}
}
handleAdd() {
const { firstname, lastname, email, phone} = this.state;
const ID = uuid();
const newItemObject = {
key: ID,
firstname: firstname,
lastname: lastname,
email: email,
phone: phone,
image: null,
};
this.setState(prevState => ({
list: [...prevState.list, newItemObject]
}));
this.saveItems(this.state.list);
}
saveItems = list => {
AsyncStorage.setItem(LIST_STORAGE_KEY, JSON.stringify(list));
};
You are not saving your list but getting keys from the list. const obj = Object.keys(parsedList); you are saving array indexes to state.
getDataSync = async () => {
try {
const list = await AsyncStorage.getItem(LIST_STORAGE_KEY);
const parsedList = JSON.parse(list);
this.setState({
isDataReady: true,
list: Array.isArray(parsedList) && parsedList.length && parsedList || []
});
} catch (e) {
Alert.alert('Failed to load list.');
}
}
Also pass saveItems as a callback to save the correct data.
this.setState(prevState => ({
list: [...prevState.list, newItemObject]
}), () => this.saveItems(this.state.list));
The .setState() method is may be asynchronous, so the result of setting the state, cannot be used immediately after setting it. If you want to use the results of setting the state, you should use the callback (2nd param), which is called after the state is actually set:
this.setState(
prevState => ({
list: [...prevState.list, newItemObject]
}),
() => this.saveItems(this.state.list)
);
i try to return all object the !== from the object that i deleted now and the filter delete all object with the same name that i clicked.
In my application it is possible to have several identical objects and I want that at the moment of deletion it will be deleted only 1.
here the code
handleClick = packageID => {
let array = [];
packageMethods
.deletePackageFromUser(packageID, this.props.userID)
.then(res => {
packageMethods.findPackage(packageID).then(temppackage => {
array = this.state.package.filter(item => {
return item._id !== temppackage.data[0]._id;
});
this.setState({
package:array
})
});
});
};
You want to find the index of the first instance of an object with that id, then remove the item at that index.
handleClick = packageID => {
let array = [...this.state.package];
packageMethods
.deletePackageFromUser(packageID, this.props.userID)
.then(res => {
packageMethods.findPackage(packageID).then(temppackage => {
const removal_index = array.findIndex(item => {
return item._id === temppackage.data[0]._id;
});
array.splice(removal_index, 1);
this.setState({
package: array
})
});
});
};
Here's an example
const arr = [{id: 1, val: 'a'}, {id: 1, val: 'a'}, {id: 2, val: 'b'}];
console.log(arr);
const removal_index = arr.findIndex(el => el.id == 1); // find index of first object with id of 1
arr.splice(removal_index,1); // remove 1 element starting at `removal_index`
console.log(arr);
I'm trying to remove a specific item from an objects array based on the title attribute in the array. I keep running into a problem where I can view the array item, but I'm not able to splice the item out of the array based on the parameters entered in my remove function. I'm just getting the error message back from my else statement in the function.
I've tried using find, forEach, findIndex and match that case in order to test out removing the result based on the index, or the text value of the key 'text'. I commented out all of the functions I tried prior to searching for the answer in the forum recommendations. All of my recipe functions are working, along with my createIngredient function, which adds an object to the recipe array. But the removeIngredient function I've been trying to get to work, isn't because of the problems mentioned above.
let recipes = []
// Read existing recipes from localStorage
const loadRecipes = () => {
const recipesJSON = localStorage.getItem('recipes')
try {
return recipesJSON ? JSON.parse(recipesJSON) : []
} catch (e) {
return []
}
}
// Expose recipes from module
const getRecipes = () => recipes
const createRecipe = () => {
const id = uuidv4()
const timestamp = moment().valueOf()
recipes.push({
id: id,
title: '',
body: '',
createdAt: timestamp,
updatedAt: timestamp,
ingredient: []
})
saveRecipes()
return id
}
// Save the recipes to localStorage
const saveRecipes = () => {
localStorage.setItem('recipes', JSON.stringify(recipes))
}
// Remove a recipe from the list
const removeRecipe = (id) => {
const recipeIndex = recipes.findIndex((recipe) => recipe.id === id)
if (recipeIndex > -1) {
recipes.splice(recipeIndex, 1)
saveRecipes()
}
}
// Remove all recipes from the recipe array
const cleanSlate = () => {
recipes = []
saveRecipes()
}
const updateRecipe = (id, updates) => {
const recipe = recipes.find((recipe) => recipe.id === id)
if (!recipe) {
return
}
if (typeof updates.title === 'string') {
recipe.title = updates.title
recipe.updatedAt = moment().valueOf()
}
if (typeof updates.body === 'string') {
recipe.body = updates.body
recipe.updateAt = moment().valueOf()
}
saveRecipes()
return recipe
}
const createIngredient = (id, text) => {
const recipe = recipes.find((recipe) => recipe.id === id)
const newItem = {
text,
have: false
}
recipe.ingredient.push(newItem)
saveRecipes()
}
const removeIngredient = (id) => {
const ingredient = recipes.find((recipe) => recipe.id === id)
console.log(ingredient)
const allIngredients = ingredient.todo.forEach((ingredient) => console.log(ingredient.text))
// const recipeIndex = recipes.find((recipe) => recipe.id === id)
// for (let text of recipeIndex) {
// console.log(recipdeIndex[text])
// }
// Attempt 3
// if (indexOfIngredient === 0) {
// ingredientIndex.splice(index, 1)
// saveRecipes()
// } else {
// console.log('error')
// }
// Attempt 2
// const recipe = recipes.find((recipe) => recipe.id === id)
// const ingredients = recipe.todo
// // let newItem = ingredients.forEach((item) => item)
// if (ingredients.text === 'breadcrumbs') {
// ingredients.splice(ingredients, 1)
// saveRecipes()
// }
// Attempt 1
// const ingredientName = ingredients.forEach((ingredient, index, array) => console.log(ingredient, index, array))
// console.log(ingredientName)
// const recipeIndex = recipes.findIndex((recipe) => recipe.id === id)
// if (recipeIndex > -1) {
// recipes.splice(recipeIndex, 1)
// saveRecipes()
// }
}
recipes = loadRecipes()
OUTPUT
{id: "ef88e013-9510-4b0e-927f-b9a8fc623450", title: "Spaghetti", body: "", createdAt: 1546878594784, updatedAt: 1546878608896, …}
recipes.js:94 breadcrumbs
recipes.js:94 noodles
recipes.js:94 marinara
recipes.js:94 meat
recipes.js:94 ground beef
recipes.js:94 milk
So I'm able to view the output I printed above and see each item in the ingredients array, but trying to splice the item based on the index number or key is not working for me with the functions I have already tried and the info I have found on Stackoverflow about objects, arrays and the splice method so far.
If I am understanding correctly (after reading the commented out attempts in your code), you are trying to remove the "breadcrumbs" ingredient from the recipe that corresponds to the id passed to the removeIngredient() function.
In that case, perhaps you could take a slightly different approach to removing the ingredient from the recipes todo array, via the Array#filter method?
You could use filter() in the following way to "filter out" (ie remove) the "breadcrumbs" ingredient from the todo array via the following filter logic:
// Keep any ingredients that do not match ingredient (ie if ingredient
// equals "breadcrumbs")
todo.filter(todoIngredient => todoIngredient !== ingredient)
You might consider revising your removeIngredient() function by;
adding an additional ingredient parameter to the function arguments. This allows you to specify the ingredient to be removed from the recipe corresponding to recipeId
and, introducing the filter() idea as described:
const removeIngredient = (recipeId, ingredient) => {
const recipe = recipes.find(recipe => recipe.id === recipeId)
if(recipe) {
// Filter recipe.todo by ingredients that do not match
// ingredient argument, and reassign the filtered array
// back to the recipie object we're working with
recipe.todo = recipe.todo.filter(todoIngredient =>
(todoIngredient !== ingredient));
}
}
Now, when you introduce the "remove" button for each ingredient, you would call the removeIngredient() as follows:
var recipeId = /* got id from somewhere */
var ingredientText = /* got ingredient from somewhere */
removeIngredient( recipeId, ingredientText );
Hope this helps!