Как реализовать отдельное управление для каждого нового созданного счетчика?
Есть простой счетчик и кнопки управления ним, + добавляет единицу, а - отнимает, так же при нажатии кнопки create создается новый счетчик.
Нужно чтобы каждый новый созданный счетчик управлялся отдельно, я пытался сделать делегирование но у меня не получилось, при создании нового счетчика и нажатии на + или - единица добавляется или отнимается в первом элементе. Что-то я упускаю!
jsfiddle - https://jsfiddle.net/ua52s0kq/
<button class = 'create'>Create</button>
<div id='container'>
<div id='menu'>
<div class = 'dayy'>
<button class='minus'>-</button>
День <span class='value'>0</span>
<button class='plus'>+</button>
</div>
</div>
</div>
const menu = document.querySelector('#menu');
const container = document.querySelector('#container');
const day = document.querySelector('.dayy');
const create = document.querySelector('.create');
const getMinus = document.querySelector('.minus');
const getPlus = document.querySelector('.plus');
const getValue = document.querySelector('.value');
let currentValue = 0;
container.addEventListener('click', e => {
if (e.target.classList.contains('plus')) {
currentValue++;
getValue.innerHTML = currentValue;
}
});
container.addEventListener('click', e => {
if (e.target.classList.contains('minus')) {
if (currentValue > 0) {
currentValue--;
getValue.innerHTML = currentValue;
}
}
});
create.addEventListener('click', () => {
let elem = document.createElement('div');
elem.setAttribute('class', 'dayy');
elem.innerHTML = '<button class='minus'>-</button> День <span class='value'>0</span> <button class="plus">+</button>';
menu.append (elem);
});
Ответы (2 шт):
Ошибка в том, что независимо от созданных элементов, у вас currentValue всегда хранит число для первого элемента, и getValue - также ссылается на первый элемент.
Вообще говоря, принято использовать HTML для отображения данных, а не их хранения. Но если вы и так предоставляете способ изменения чисел, не случится ничего страшного, если использовать textContent для получения текущего числа:
const _first = (str, root) => (root || document).querySelector(str);
_first("#container").addEventListener('click', function({target}) {
if (target.matches(".plus")) {
let elem = _first(".value", target.closest(".dayy"));
// Первый .value внутри ближайшего .dayy (идет как параметр `root`)
elem.textContent = Number(elem.textContent) + 1;
return;
}
if (target.matches(".minus")) {
let elem = _first(".value", target.closest(".dayy"));
elem.textContent = Math.max(0, elem.textContent - 1);
return;
}
});
_first(".create").addEventListener('click', function() {
_first("#menu").insertAdjacentHTML("beforeEnd", `
<div class="dayy">
<button class="minus">-</button>
День <span class="value">0</span>
<button class="plus">+</button>
</div>
`);
// `Обратные` кавычки допускают многострочную запись.
// При этом, между элементами появляются пробелы: иногда это может помешать.
});
<button class = "create">Create</button>
<div id="container">
<div id="menu">
<div class = "dayy">
<button class="minus">-</button>
День <span class="value">0</span>
<button class="plus">+</button>
</div>
</div>
</div>
Если бы очень хотелось хранить число-счетчик в переменной, можно было бы завести массив:
const _first = (str, root) => (root || document).querySelector(str);
const _all = (str) => document.querySelectorAll(str);
let counters = [0];
_first("#container").addEventListener('click', function({target}) {
let day = target.closest(".dayy");
if (!day) return;
let index = [..._all(".dayy")].indexOf(day);
// номер текущего элемента среди всех остальных (google → spread оператор)
let diff = target.matches(".plus") ? 1 : target.matches(".minus") ? -1 : 0;
// +1, -1 или 0 — смотря куда кликнули.
_first(".value", day).textContent = Math.max(0, counters[index] += diff);
// counters[index] += diff значение в массиве в соответствующей позиции
// меняется на +1 / -1 / 0, возвращается результат присваивания,
// который попадает в textContent
});
_first(".create").addEventListener('click', function() {
_first("#menu").insertAdjacentHTML("beforeEnd", `
<div class="dayy">
<button class="minus">-</button>
День <span class="value">0</span>
<button class="plus">+</button>
</div>
`);
counters.push(0);
// При создании каждого нового элемента, для него добавляется и счетчик
// Номер счетчика в массиве - будет соответствовать
// номеру HTML-элемента среди остальных таких же.
});
<button class = "create">Create</button>
<div id="container">
<div id="menu">
<div class = "dayy">
<button class="minus">-</button>
День <span class="value">0</span>
<button class="plus">+</button>
</div>
</div>
</div>
P.s. Конечно же, в реальном коде не стал бы "умничать", а записал бы через обычные if-else.
P.p.s. Можете посмотреть, что такое функции-конструкторы / замыкание, попробовать реализовать через них)
Используя HTML для отображения данных:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title> counters </title>
</head>
<body>
<div class="container"></div>
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<script>
"use strict"
const { useEffect, useState } = React
const e = React.createElement
const App = () => {
const [ items, setItems ] = useState([0])
const changeValue = (cPos,delta) => setItems(cItems=>cItems.map((value,pos) => (
pos !== cPos ? value : Math.max(0, value+delta)
)))
const addCounter = () => setItems(cItems=>[...cItems,0])
return [
e("button", { key: "create", className: "create", onClick: ev => addCounter() }, "Create"),
e("div", { key: "container", className: "container" },
e("div", { className: "menu" },
items.map((value,pos) =>(
e("div", { key: pos, className: "dayy" },
e("button", { key: "m", className: "minus", onClick: ev=>changeValue(pos,-1) }, "-"),
" День ", e("span", { key: "v", className: "value" }, value),
e("button", { key: "p", className: "plus", onClick: ev=>changeValue(pos,+1) }, "+"),
)
))
)
)
]
}
ReactDOM.render(e(App), document.querySelector('.container'))
</script>
</body>
</html>