Search code examples
javascriptarraysformsduplicatesuser-input

Novice coder question - JS User-generated shopping list - How to update number property of list objects and avoid duplicates


e.g. if a user submits "tacos" twice, instead of having two lines, each containing "tacos", I want to have one line with "tacos x 2". Question 2 - is it possible to create a variable that selects every item in an array except another variable? e.g.

for (let i = 0; i < items.length; i++)
{let j = !i;
}

(I am aware the above code is incorrect, I included it only to illustrate my question)

Thank you in advance.

 // key function out of context
 if (!items.includes(item.text)) {
 items.push(item);
 } else {
  items.item.number =+1
 }


 //entire html file with script including key function in context

 <!DOCTYPE html>
 <html lang="en">
 <head>
 <meta charset="UTF-8">
 <title>LocalStorage</title>
 <link rel="stylesheet" href="style.css">
 </head>
 <body>


 <div class="wrapper">
 <h2>LOCAL TAPAS</h2>
 <p></p>
 <ul class="plates">
  <li>Loading Tapas...</li>
 </ul>
 <form class="add-items" autocomplete="off">
  <input type="text" name="item" placeholder="Item Name" required>
  <input type="submit" value="+ Add Item">
 </form>
 <button type="reset" value="reset"">clear all</button>
 <button class="select">Select all</button>
 </div>

 <script>

 const addItems = document.querySelector('.add-items');
 const itemsList = document.querySelector('.plates');
 const selectAll = document.querySelector('.select');
 const items = [];
 const mySet = new Set();
 const userInput = document.querySelector('[type="text"]');
 // add items to list

 // populate list with html

  function add(e) {
  e.preventDefault();
  console.dir(e.currentTarget)
  const text = e.currentTarget.item.value;

  const item = {
    text,
    done:false,
    number: 1,
  };

  console.dir(item)

  
 if (!items.includes(item.text)) {
 items.push(item);
 } else {
 items.item.number =+1
 }



  e.currentTarget.reset();

  itemsList.dispatchEvent(new CustomEvent('itemsUpdated'))

  }

 function displayItems(item, i) {
 const html = items.map((item, i) => `
 <li>
 <input type="checkbox">
 <label name="${item}" id="${i}"><strong>${item.text}</strong> x${item.number}             </label>
</li>`).join('');

itemsList.innerHTML = html;

};






  addItems.addEventListener('submit', add)
 itemsList.addEventListener('itemsUpdated', displayItems)



 </script>


 </body>
 </html>

Solution

  • The problem lies with how you're checking if your item object is in the items array.

    Since the elements of your array are objects, you would need to modify that checkup - includes and indexOf won't work.

    What you would need to do is:

    let indx = items.findIndex(element => element.text === item.text);
    

    array.findIndex will let you find an element within an array which satisfies the given condition. In this case, you want to find a specific product by name. That's why we're doing the element.text === item.text comparison.

    Check the updated example below, to see it in action.

    const addItems = document.querySelector('.add-items');
    const itemsList = document.querySelector('.plates');
    const selectAll = document.querySelector('.select');
    const items = [];
    const mySet = new Set();
    const userInput = document.querySelector('[type="text"]');
    // add items to list
    // populate list with html
    
    function add(e) {
        e.preventDefault();
        const text = e.currentTarget.item.value;
    
        const item = {
            text,
            done:false,
            number: 1,
        };
    
        /* these are the key changes */
        let indx = items.findIndex(element => element.text === item.text);
    
        if (indx < 0) {
            items.push(item);
        } else {
            items[indx].number += 1;
        }
        /* */
    
        e.currentTarget.reset();
        itemsList.dispatchEvent(new CustomEvent('itemsUpdated'))
    }
    
    function displayItems(item, i) {
        const html = items.map((item, i) => `
            <li>
                <input type="checkbox">
                <label name="${item}" id="${i}"><strong>${item.text}</strong> x${item.number}</label>
            </li>
        `).join('');
    
        itemsList.innerHTML = html;
    };
    
    addItems.addEventListener('submit', add)
    itemsList.addEventListener('itemsUpdated', displayItems)
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>LocalStorage</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div class="wrapper">
            <h2>LOCAL TAPAS</h2>
            <p></p>
            <ul class="plates">
                <li>Loading Tapas...</li>
            </ul>
            <form class="add-items" autocomplete="off">
                <input type="text" name="item" placeholder="Item Name" required>
                <input type="submit" value="+ Add Item">
            </form>
            <button type="reset" value="reset">clear all</button>
            <button class="select">Select all</button>
        </div>
    </body>
    </html>

    EDIT There were also minor syntax error edits:

    • in your original code, your reset button had this as its value - value="reset"". I've removed the extra quote.
    • your initial incrementing of item.number was also erroneous - instead of items.item.number =+1 it should have been (as it is now) items[indx].number += 1. Note that it's += and not =+.