0

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 class="review-screen-ingred-name"> ${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.

2 Answers 2

1

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 class="review-screen-ingred-name"> ${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?

Sign up to request clarification or add additional context in comments.

Comments

1

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 class="review-screen-ingred-name">' + 
    Object.entries(ingreds).map(([k, v]) => {
      [name, capacity] = k.split(' - ')
      return `<p>${name} - ${v} bottles ${capacity}</p>`
    }).join('')
}

document.write(loadData(cocktails))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.