Remove an array item nested inside of an object - javascript

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!

Related

Update an array of objects with or without mutation dynamically

I am currently working a todo list project using plain JavaScript and have to create a function that updates a projects title,description, priority, etc. Is there a way to update the array of objects with or without mutation ?
An example would be something along the lines of
project1.tasks[2].title = newTitle
// Project Manager object
const PM = {
// Empty projects array
projects: [],
// Project method pushing to projects array
addProject(project) {
this.projects.push(project)
},
deleteProject(project) {
const projectIndex = this.projects.indexOf(project)
if (projectIndex !== -1) {
this.projects.splice(projectIndex, 1)
return true
}
return false
},
updateProject() {
// Update projects title, description, priority
}
}
const projectFactory = (title) => ({
title,
tasks: [],
addTask(task) {
this.tasks.push(task)
},
deleteTask(task) {
const taskIndex = this.tasks.indexOf(task)
if (taskIndex !== -1) {
this.tasks.splice(taskIndex, 1)
return true
}
return false
}
})
const createProject = (title) => {
const project = projectFactory(title)
return project
}
const taskFactory = (title, description, dueDate, priority) => ({ title, description, dueDate, priority })
const createTask = (title, description, dueDate, priority) => {
const task = taskFactory(title, description, dueDate, priority)
return task`
}
const project1 = projectFactory("Clean")
const task1 = taskFactory("Clean kitchen", "Wash dishes", "1/19/2023", "Medium")
PM.addProject(project1)
project1.addTask(task1)
I have tried to follow along on similiar problems that people have come across on StackOverflow but they're using ids or their todo list is made in React.

Update array inside object if it exists, otherwise push array to object

If the object is currently in the array I want to update some value, and if it's not I want to add it to the array. This is the solution I have below, which I don't feel is the best/correct way to do it.
const handleAddToCart = product => {
const newList = [...cart]
if (!newList.includes(product)) {
newList.push(product)
} else {
const productIndex = newList.findIndex((obj => obj._id === product._id))
newList[productIndex].prop = "Some value"
}
setCart(newList)
}
Thank you.
You have to be pretty careful here, as there are a few gotchas with object comparison and mutating the state ([...cart] is not sufficient in deep copying cart). You can update the state in a pure fashion as follows, although I would recommend something like Redux for complex state management.
const handleAddToCart = product => {
const index = cart.findIndex(obj => obj._id === product._id)
if (index === -1) {
setCart(cart.concat(product))
} else {
setCart([
...cart.slice(0, index),
Object.assign({}, product, { prop: "Some value" }),
...cart.slice(index + 1),
])
}
}
const handleAddToCart = productToAdd => {
const newList = [...cart];
const existent = newList.find(product => product.id === productToAdd.id);
if(existent) {
existent.prop = "prop";
} else {
newList.push(productToAdd);
}
setCart(newList);
}

Delete Function using .filter Method

I am creating a note taking app and am getting stuck on my deleteNote function. I am needing to use the .filter method to remove notes w/ an assigned id and keep the ones not associated to that id. Here is my code so far.
const fs = require("fs");
const util = require("util");
// returns a unique ID for our returns
const uuidv1 = require("uuid/v1");
// creates a promified version of fs.readfile and writefile
const readFileAsync = util.promisify(fs.readfile);
const writeFileAsync = util.promisify(fs.writefile);
class Store {
read() {
return readFileAsync("./db/db.json", "utf8");
}
write(note) {
return writeFileAsync("./db/db.json", JSON.stringify(note));
}
getNotes() {
return this.read().then(notes => {
let parsedNotes;
try {parsedNotes = [].concat(JSON.parse(notes))}
catch (err) {
parsedNotes = [];
}
return parsedNotes;
})
}
// example of destructuring -- im taking the title, text string and destructuring it to add a unique id.
addNote(note) {
const {title, text} = note;
const newNote = {title, text, id: uuidv1()};
return this.getNotes()
.then(notes => [...notes, newNote]);
.then(updatedNotes => this.write(updatedNotes));
.then(() => newNote);
}
// delete note is going to take in an id and use a .filter to only keep the notes that do not include that id.
deleteNote() {
}
}
module.exports = new Store();
You already know you're filtering, so just do it:
deleteNote(id) {
return this.getNotes()
.then(notes => notes.filter(note => note.id !== id))
.then(updatedNotes => this.write(updatedNotes));
}
Try this one which includes returning deleted note.
async deleteNote(id) {
const notes = await this.getNotes();
const filtered = notes.filter((note) => note.id !== id);
await this.write(filtered);
const deleted = notes.filter((note) => note.id === id);
return deleted;
}

Firebase check if an array of values exist before posting in DB

I'm currently building an app using vue.js and firebase as backend and I'm checking whether a value already exists in the database by doing so:
addItem ({commit}, payload) {
const footprint = payload.footprint
firebase.database().ref('ecologic/footprint').once('value', snapshot => {
const obj = snapshot.val()
let objExists
for (let key in obj) {
if (obj[key] === footprint) objExists = true
else objExists = false
}
if (!objExists) {
firebase.database().ref(`ecologic/footprint`).push(footprint)
}
})
},
How can I extend this functionality to compare an array's value with another array and post to firebase if the value doesn't exists yet.
I tried to use double loop but was not working since I'm using a boolean. Is there a nicer way to do it? Thank you
I tried another way but this time console.log is always returning true
firebase.database().ref('ecologic/footprint').once('value', snapshot => {
const objSnap = snapshot.val()
const loadedFootp = []
for (let key in objSnap) {
loadedFootp.push(objSnap[key])
}
for (let obj in footprint) {
const newFootp = footprint[obj]
const objExists = footprint.some((newFootp) => loadedFootp.indexOf(newFootp) !== -1);
console.log(objExists)
}
})
Found a way by doing so:
firebase.database().ref('ecologic/footprint').once('value', snapshot => {
const objSnap = snapshot.val()
const loadedFootp = []
for (let key in objSnap) {
loadedFootp.push(objSnap[key])
}
for (let obj in footprint) {
if (loadedFootp.some(item => item === footprint[obj])) {
} else {
console.log(footprint[obj])
}
}
})

Rewrite a function to find an object by a matching id inside an array, update a value and set a react state

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 });

Categories

Resources