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 >
<img src="${this.parentElement.children[0].src}" alt="" />
<div>
<h4 >${this.parentElement.children[1].textContent}</h4>
<div >
<button >
<i ></i>
</button>
<p >1</p>
<button >
<i ></i>
</button>
</div>
</div>
<button >
<i ></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);
});
});
CodePudding user response:
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 type="button" value="1">
<input type="button" value="2">
<input type="button" value="3">
<input type="button" value="4">
<input type="button" value="5">
<input type="button" value="6">
<input 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 type="button" value="1">
<input type="button" value="2">
<input type="button" value="3">
<input type="button" value="4">
<input type="button" value="5">
<input type="button" value="6">
<input 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 >
<img src="${this.parentElement.children[0].src}" alt="" />
<div>
<h4 >${this.parentElement.children[1].textContent}</h4>
<div >
<button >
<i ></i>
</button>
<p >1</p>
<button >
<i ></i>
</button>
</div>
</div>
<button >
<i ></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 >
<img src="${this.parentElement.children[0].src}" alt="" />
<div>
<h4 >${this.parentElement.children[1].textContent}</h4>
<div >
<button >
<i ></i>
</button>
<p >1</p>
<button >
<i ></i>
</button>
</div>
</div>
<button >
<i ></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);
});
});
CodePudding user response:
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();