I'm trying to do a shopping list generator (client selects cocktails and an ingredients list is generated) and I'm just stuck on this part. I have the following code:
There's a 'data' set which contains the arrays for all the cocktails and their ingredients but it's too big to paste here. 'savedData' is the selected cocktails ingredients.
function loadData(savedData) {
let selectedCocktailsHTML = ``;
savedData.cocktailsList.forEach(item => {
let selectedIngredients = ``;
if (item.isChecked) {
item.ingredients.forEach(ingred => {
selectedIngredients = `<p>${ingred.name} - ${ingred.selectedQty} ${ingred.capacity}</p>`;
});
selectedCocktailsHTML = `<p > ${selectedIngredients}`;
}
});
And it gives me an output like this:
Vodka - 1 bottles 1L
Peach Schnapps - 1 bottles 1L
Cranberry Juice - 2 bottles 1L
Coffee Liqueur - 1 bottles 1L
Vodka - 1 bottles 1L
What I would like to do is to loop through and combine the duplicate values when the user selects them (such as vodka in this case) and then add the quantities of each one together. My desired output for this example would be:
Vodka - 2 bottles 1L
Peach Schnapps - 1 bottles 1L
Cranberry Juice - 2 bottles 1L
Coffee Liqueur - 1 bottles 1L
Can anyone help with the best way to go about this? Theres a lot of the code I didn't add, let me know if you need more to work it out.
CodePudding user response:
I'm not sure how's your savedData struct look like, but if you want combine the same product's quantities. I will do like this:
//loadData function
function loadData(savedData) {
let selectedCocktailsHTML = ``;
let ingredientsInfo = {};
savedData.cocktailsList.forEach(item => {
if (item.isChecked) {
item.ingredients.forEach(ingred => {
if(!ingredientsInfo[ingred.name]){
ingredientsInfo[ingred.name] = {
capacity:ingred.capacity,
count:1
};
}
else{
ingredientsInfo[ingred.name].count ;
}
});
}
});
for(let i = 0; i < Object.keys(ingredientsInfo).length; i ){
let name = Object.keys(ingredientsInfo)[i];
let count = ingredientsInfo[name].count;
let capacity = ingredientsInfo[name].capacity;
let selectedIngredients = `<p>${name} - ${count} ${capacity}</p>`;
selectedCocktailsHTML = `<p > ${selectedIngredients}`;
}
return selectedCocktailsHTML;
}
//function test
loadData({
cocktailsList:[
{
ingredients:[
{
name:"Vodka",
selectedQty:1,
capacity:"bottles 1L"
}
],
isChecked:true
},
{
ingredients:[
{
name:"Vodka",
selectedQty:1,
capacity:"bottles 1L"
}
],
isChecked:true
}
]
});
Is this what you want?
CodePudding user response:
Rather than a forEach
over the cocktailsList
I would use reduce to add all the quantities of each ingredient into an object. Then you can build the result HTML from iterating that object:
cocktails = { cocktailsList: [
{ ingredients : [
{ name : 'Vodka', capacity : '1L', selectedQty : 1 },
{ name : 'Peach Schnapps', capacity : '1L', selectedQty : 1 },
{ name : 'Cranberry Juice', capacity : '1L', selectedQty : 2 }
],
isChecked : 1
},
{ ingredients : [
{ name : 'Coffee Liqueur', capacity : '1L', selectedQty : 1 },
{ name : 'Vodka', capacity : '1L', selectedQty : 1 }
],
isChecked : 1
}
]
}
function loadData(savedData) {
const ingreds = savedData.cocktailsList.reduce((acc, item) => {
if (item.isChecked) {
item.ingredients.forEach(ingred => {
key = `${ingred.name} - ${ingred.capacity}`
acc[key] = (acc[key] || 0) ingred.selectedQty
})
}
return acc
}, {})
return '<p >'
Object.entries(ingreds).map(([k, v]) => {
[name, capacity] = k.split(' - ')
return `<p>${name} - ${v} bottles ${capacity}</p>`
}).join('')
}
document.write(loadData(cocktails))