简体   繁体   中英

Increment and Decrement: Javascript

I am doing an e-commerce project. I am currently trying to create the functionality of the quantity amount for each new added item. However, when the amount of one item altered, though it does not change the other item's quantity, when you try to alter the other item's quantity it starts from the number of the previous item's quantity.

For example, if I make the quantity of 'item1' = 3. Then if I adjust 'item2', whether I increase or decrease, it starts from 3, instead of 1.

I think I am maybe complicating it for myself I am still new to JavaScript.

const quantityIncDec = function (plus, minus) {
  let quantity = 1;

  plus.forEach(button => {
    button.addEventListener('click', function () {
      quantity++;
      this.parentElement.children[1].textContent = quantity;
    });
  });

  minus.forEach(button => {
    button.addEventListener('click', function () {
      if (quantity > 1) {
        quantity--;
        this.parentElement.children[1].textContent = quantity;
      }
    });
  });
};

// Add to Cart Preview
btnAddCart.forEach(element => {
  element.addEventListener('click', function () {
    const markup = `
    <li class="index-preview-list-item">
    <img src="${this.parentElement.children[0].src}" alt="" />
      <div>
        <h4 class="product-name">${this.parentElement.children[1].textContent}</h4>
        <div class="quantity">
          <button class="btn btn-plus">
            <i class="fa-solid fa-plus"></i>
          </button>
          <p class="quantity-value">1</p>
          <button class="btn btn-minus">
            <i class="fa-solid fa-minus"></i>
          </button>
        </div>
      </div>
      <button class="btn btn-delete">
        <i class="fa-solid fa-trash-can"></i>
      </button>
    </li>
    `;

    clearPreviewText(previewTextCart);
    cartPreviewContainer.insertAdjacentHTML('beforeend', markup);

    const btnPlus = document.querySelectorAll('.btn-plus');
    const btnMinus = document.querySelectorAll('.btn-minus');
    quantityIncDec(btnPlus, btnMinus);

    const btnDelete = document.querySelectorAll('.btn-delete');
    deleteItem(btnDelete);
  });
});

I'm not sure, If I understood your question correctly. The problem in your source code is, that the only single quantity variable you are using for all of your products. But each product has it's own quantity state, therefore In your case, If you will modify quantity of one product, you will also modify initial quantity state of all another products.

Inside listener callback method, you must firstly get the previous quantity state for the current product and after that increment that value. Also another way is for example save current product quantities into array variable, and then you will need firstly find the initial quantity state from right array value, then increment and then save back modified value to that array.

// ...or ungly but most simple solution, take text content, convert to Int, then increment and store back to the element
this.parentElement.children[1].textContent = parseInt(this.parentElement.children[1].textContent)+1;

Edited answer:


// Write Javascript code!
const appDiv = document.getElementById('app');
appDiv.innerHTML = `<div id="basket">Basket</div>`;

let items = [
  {
    id: 24,
    name: 'halabala',
    qty: 10,
  },
];

function Basket() {
  const render = () => {
    const elBasket = document.getElementById('basket');
    elBasket.innerHTML = ''; // Remove all childs from previous render
    // console.log(elBasket);

    if (items.length) {
      items.forEach((item) => {
        const that = this;
        const elDiv = document.createElement('div');

        const elSpan = document.createElement('span');
        elSpan.innerText = '   ' + item.name + ' (' + item.qty + ')';

        const btnPlus = document.createElement('button');
        btnPlus.innerText = '+';
        btnPlus.addEventListener('click', (event) => {
          event.preventDefault();
          Basket().incrementItem(item.id);
        });

        const btnMinus = document.createElement('button');
        btnMinus.innerText = '-';
        btnMinus.addEventListener('click', (event) => {
          event.preventDefault();
          Basket().decrementItem(item.id);
        });

        elDiv.appendChild(btnPlus);
        elDiv.appendChild(btnMinus);
        elDiv.appendChild(elSpan);
        elBasket.appendChild(elDiv);
      });
    }
  };

  return {
    init: () => {
      render();
    },

    addItem: (itemId, itemName, gty = 1) => {
      items.push({ id: itemId, name: itemName, qty: qty });
      render();
    },

    removeItem: (itemId) => {
      items = items.filter((i) => i.id != itemId);
      render();
    },

    incrementItem: (itemId) => {
      const item = items.find((i) => i.id === itemId);
      if (!item)
        throw new Error('Unable to increment, because item not found!');

      item.qty++;
      render();
    },

    decrementItem: (itemId) => {
      const item = items.find((i) => i.id === itemId);
      if (!item)
        throw new Error('Unable to decrement, because item not found!');

      item.qty--;
      render();
    },

    clearBasket: () => {
      items = [];
    },
  };
}

Basket().init();

The let keyword is used to create a block-scoped variable. So, you will have a single instance of that variable in its block. Let's illustrate this in two examples:

 let quantity = 0; for (let button of document.querySelectorAll(".btn")) { button.addEventListener("click", function() { alert(++quantity); }); }
 <input class="btn" type="button" value="1"> <input class="btn" type="button" value="2"> <input class="btn" type="button" value="3"> <input class="btn" type="button" value="4"> <input class="btn" type="button" value="5"> <input class="btn" type="button" value="6"> <input class="btn" type="button" value="7">

As you can see, the counter is being updated whenever you click on a button and it does not separately keep track of each button's quantity . This is your mistake. Now, let's see a corrected example, where quantity is created in the correct block:

 for (let button of document.querySelectorAll(".btn")) { let quantity = 0; button.addEventListener("click", function() { alert(++quantity); }); }
 <input class="btn" type="button" value="1"> <input class="btn" type="button" value="2"> <input class="btn" type="button" value="3"> <input class="btn" type="button" value="4"> <input class="btn" type="button" value="5"> <input class="btn" type="button" value="6"> <input class="btn" type="button" value="7">

If you click on different buttons here, then you will see that each is having "its own" quantity . So, having said this, let's apply a similar fix for your code:

const quantityIncDec = function (plus, minus) {
  //quantity is no longer defined here, because then it's out of the loop's
  //block and its value will be shared between the buttons

  plus.forEach(button => {
    //Instead, we create quantity here and it will be therefore in the
    //context of the "current" button
    let quantity = 1;
    button.addEventListener('click', function () {
      quantity++;
      this.parentElement.children[1].textContent = quantity;
    });
  });

  minus.forEach(button => {
    button.addEventListener('click', function () {
      if (quantity > 1) {
        quantity--;
        this.parentElement.children[1].textContent = quantity;
      }
    });
  });
};

// Add to Cart Preview
btnAddCart.forEach(element => {
  element.addEventListener('click', function () {
    const markup = `
    <li class="index-preview-list-item">
    <img src="${this.parentElement.children[0].src}" alt="" />
      <div>
        <h4 class="product-name">${this.parentElement.children[1].textContent}</h4>
        <div class="quantity">
          <button class="btn btn-plus">
            <i class="fa-solid fa-plus"></i>
          </button>
          <p class="quantity-value">1</p>
          <button class="btn btn-minus">
            <i class="fa-solid fa-minus"></i>
          </button>
        </div>
      </div>
      <button class="btn btn-delete">
        <i class="fa-solid fa-trash-can"></i>
      </button>
    </li>
    `;

    clearPreviewText(previewTextCart);
    cartPreviewContainer.insertAdjacentHTML('beforeend', markup);

    const btnPlus = document.querySelectorAll('.btn-plus');
    const btnMinus = document.querySelectorAll('.btn-minus');
    quantityIncDec(btnPlus, btnMinus);

    const btnDelete = document.querySelectorAll('.btn-delete');
    deleteItem(btnDelete);
  });
});

EDIT

The solution above was ignoring that a minus button also has to work with the same quantity, so I apply a fix for it:

const quantityIncDec = function (plus, minus) {
  //quantity is no longer defined here, because then it's out of the loop's
  //block and its value will be shared between the buttons
  let limit = Math.max(plus.length, minus.length);
  for (index = 0; index < limit; index++) {
    if (plus.length > index) {
      let plusButton = plus[index];
      plusButton.addEventListener('click', function () {
        quantity++;
        this.parentElement.children[1].textContent = quantity;
      });
    }
    if (minus.length > index) {
      let minusButton = minus[index];
      minusButton.addEventListener('click', function () {
        if (quantity > 1) {
          quantity--;
          this.parentElement.children[1].textContent = quantity;
        }
      });
    }
  }

};

// Add to Cart Preview
btnAddCart.forEach(element => {
  element.addEventListener('click', function () {
    const markup = `
    <li class="index-preview-list-item">
    <img src="${this.parentElement.children[0].src}" alt="" />
      <div>
        <h4 class="product-name">${this.parentElement.children[1].textContent}</h4>
        <div class="quantity">
          <button class="btn btn-plus">
            <i class="fa-solid fa-plus"></i>
          </button>
          <p class="quantity-value">1</p>
          <button class="btn btn-minus">
            <i class="fa-solid fa-minus"></i>
          </button>
        </div>
      </div>
      <button class="btn btn-delete">
        <i class="fa-solid fa-trash-can"></i>
      </button>
    </li>
    `;

    clearPreviewText(previewTextCart);
    cartPreviewContainer.insertAdjacentHTML('beforeend', markup);

    const btnPlus = document.querySelectorAll('.btn-plus');
    const btnMinus = document.querySelectorAll('.btn-minus');
    quantityIncDec(btnPlus, btnMinus);

    const btnDelete = document.querySelectorAll('.btn-delete');
    deleteItem(btnDelete);
  });
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM