проблема со счетчиком товара в корзине

Не правильно работает счетчик товара, чем больше товаров тем больше счетчик +-.

Структура кода.

При нажатии кнопки добавить в корзину:

$('.btn-add-cart').click(function(e){
createCartElement(); });

Идет вызов функции в которой, при каждом нажатии, создается карточка с товаром:

out += '<button class="btn-counter minus"><p class="btn-text">-</p></button>';
out += '<input class="counter" value="1">';
out += '<button class="btn-counter plus"><p class="btn-text">+</p></button>';

cartItem.innerHTML = out;
cartItems.append(cartItem);

Внутри этой же функции обрабатывается нажатие на кнопки + и - с выводом счетчика:

$('.btn-counter.plus').click(function(e) {

  let input = parseInt(e.target.parentElement.parentElement.children[1].value);
  input = input + 1;
  e.target.parentElement.parentElement.children[1].value = input;
});

$('.btn-counter.minus').click(function(e) {
  let input = parseInt(e.target.parentElement.parentElement.children[1].value);
  input = input - 1;
  e.target.parentElement.parentElement.children[1].value = input;
  if (input == 0) {
    input = 1;
  }
});

И так, суть проблемы заключается в том, что при первом нажатии на кнопку (добавить в корзину)- добавляется один товар и все работает хорошо, счетчик добавляет +1 и -1, создали еще одну, старая карточка +2 -2, а новая +1 -1 итд (+3 -3), скорее всего при создании нового элемента оно передает значение старому, прошу помочь с данной проблемой, пробовал уже разные варианты, ничего толкового не нашел.


Ответы (2 шт):

Автор решения: Gosha

это просто пример, но он показывает что надо

const wrapItems = document.querySelector('#list');

const createButton = (isAdd, elementInput) => {
  let operation;
  let cssClass;

  const btn = document.createElement('button');
  if (isAdd === true) {
    operation = '+';
    cssClass = 'plus'
    btn.onclick = () => elementInput.value = parseInt(elementInput.value, 10) + 1;
  } else {
    operation = '-';
    cssClass = 'minus';
    btn.onclick = () => elementInput.value = parseInt(elementInput.value, 10) - 1;
  }
  btn.classList.add('btn-counter', cssClass);

  btn.innerHTML = `<p class="btn-text">${operation}</p>`;

  return btn;
}

document.querySelector('#add-item').addEventListener('click', () => {
  const itemDiv = document.createElement('div');
  const input = document.createElement('input');
  input.setAttribute('type', 'text');
  input.value = 1;
  const btnPlus = createButton(true, input);
  const btnMinus = createButton(false, input);

  itemDiv.append(btnMinus, input, btnPlus);

  wrapItems.appendChild(itemDiv);
});
<button id="add-item">add</button>
<div id="list"></div>

а еще, если это допустимо, можно использовать <input type="number" step="1" min="0">

→ Ссылка
Автор решения: Yugofx

На один и тот же DOM-элемент можно вешать сколько угодно слушателей событий.

Проблема твоего решения в том, что ты вешаешь обработчики события при каждом добавлении нового счетчика, используя при этом общий селектор.

То есть, создал кнопку -> повесил события на все кнопки с селектором .btn-counter.plus. В твоем случае ход действий получился такой

1. Создать счетчик 1
2. Добавить в DOM.
3. Повесить событие на счетчик 1. (1 х1)
4. Создать счетчик 2
5. Добавить в DOM.
6. Повесить событие на счетчик 1 и 2 (1 х2, 2 х1)
7. Создать счетчик 3
8. Добавить в DOM.
9. Повесить событие на счетчик 1, 2 и 3 (1 х3, 2 х2, 3 х1)

... и тд.

Есть еще общая проблема с производительностью кода. Добавление через innerHTML заставляет лишний раз напрягаться браузерный парсер, чтобы разделить весь текст на токены и сгенерировать исполняемый код.

Лучше упростить задачу браузеру:

const createButton = (className, text, clickListener) => {
    const btn = document.createElement('button');
    btn.className = className;
    const label = document.createElement('p');
    label.className = 'btn-text';
    label.appendChild(document.createTextNode(text));
    btn.addEventListener('click', clickListener);
    btn.appendChild(label);
    return btn;
};

const createInput = () => {
    const input = document.createElement('input');
    input.className = 'counter';
    input.value = 1;
    return input;
};

const createCartElement = () =>
    cartItems.append(
        createButton('btn-counter minus', '-', removeFromCart); // TODO: implement removeFromCart
        createInput(),
        createButton('btn-counter plus', '+', addToCart); // TODO: implement addToCart
    );
}
→ Ссылка