Изменение поведения выбранных чекбоксов
У меня есть список ul с чекбоксами в каждом li.
<ul class="list"> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Buy milk</li> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Pick up Tom from airport</li> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Visit party</li> </ul> Мне нужно изменить поведения каждого li элемента при клике на соответствующий чекбокс. Делаю таким образом и у меня добавляется класс 'list__item_done' только к первому элементу li. При клике на другие чекбоксы класс 'list__item_done' не назначается. Как это исправить? const chbx = document.querySelector('.list__item-checkbox'); const li = document.querySelector('.list__item'); chbx.addEventListener('click', () => { if (chbx.checked) { li.classList.add('list__item_done'); } else { li.classList.remove('list__item_done'); } }); |
Цитата:
|
Цитата:
const chbx = document.querySelector('.list__item-checkbox'); const li = document.querySelectorAll('.list__item'); chbx.addEventListener('click', () => { for (let i = 0; i < li.length; i++) { if (chbx.checked) { li.classList.add('list__item_done'); } else { li.classList.remove('list__item_done'); } } }); Ошибка: cannot reat property undefined (reading 'add') |
NovichokJS,
:-? :-? :-? <!DOCTYPE html> <html> <head> <title>Untitled</title> <meta charset="utf-8"> <style type="text/css"> ul { list-style: none; width: 240px; } .list__item_done { background-image: -webkit-linear-gradient(left, #0000CD, #FF0000); background-image: linear-gradient(to right, #0000CD, #FF0000); color: #FFFFFF; } </style> <script> /* делегирование */ document.addEventListener("DOMContentLoaded", function() { let ul = document.querySelector(".list"); ul.addEventListener("change", function({ target }) { target.closest("li").classList.toggle("list__item_done", target.checked) }) }) /* цикл */ /* document.addEventListener("DOMContentLoaded", function() { document.querySelectorAll(".list li").forEach(li => li.addEventListener("change", function({ target }) { li.classList.toggle("list__item_done", target.checked) })) })*/ </script> </head> <body> <ul class="list"> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Buy milk</li> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Pick up Tom from airport</li> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Visit party</li> </ul> </body> </html> |
NovichokJS,
<!DOCTYPE html> <html> <head> <title>Untitled</title> <meta charset="utf-8"> <style type="text/css"> ul { list-style: none; width: 240px; } .list__item_done { background-image: -webkit-linear-gradient(left, #0000CD, #FF0000); background-image: linear-gradient(to right, #0000CD, #FF0000); color: #FFFFFF; } </style> <script> document.addEventListener("DOMContentLoaded", function() { const chbx = document.querySelector('.list'); const lis = chbx.querySelectorAll('.list__item'); chbx.addEventListener('click', () => { for (let i = 0; i < lis.length; i++) { let li = lis[i]; if (li.querySelector(":checked")) { li.classList.add('list__item_done'); } else { li.classList.remove('list__item_done'); } } }); }) </script> </head> <body> <ul class="list"> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Buy milk</li> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Pick up Tom from airport</li> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Visit party</li> </ul> </body> </html> |
NovichokJS,
<!DOCTYPE html> <html> <head> <title>Untitled</title> <meta charset="utf-8"> <style type="text/css"> ul { list-style: none; width: 240px; } .list__item_done { background-image: -webkit-linear-gradient(left, #0000CD, #FF0000); background-image: linear-gradient(to right, #0000CD, #FF0000); color: #FFFFFF; } </style> <script> document.addEventListener("DOMContentLoaded", function() { const chbx = document.querySelector('.list'); const lis = chbx.querySelectorAll('.list__item'); for (let li of lis) { li.addEventListener('click', () => { if (li.querySelector(":checked")) { li.classList.add('list__item_done'); } else { li.classList.remove('list__item_done'); } }) }; }) </script> </head> <body> <ul class="list"> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Buy milk</li> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Pick up Tom from airport</li> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Visit party</li> </ul> </body> </html> |
Рони, спасибо. А эта обёртка обязательна в данном случае? - document.addEventListener("DOMContentLoaded", function() {
такого даже не учил еще. Без нее также отработает код |
Цитата:
|
ясно. А как отсортировать выполненные(перечеркнутые таски)? чтобы те, которые чекаем спускались в самый вниз. Понимаю что надо наверное как-то сортануть массив lis, вызвав метод sort(), но как именно что и куда вставить не получается у меня
|
NovichokJS,
<!DOCTYPE html> <html> <head> <title>Untitled</title> <meta charset="utf-8"> <script> alert(document.body ? "тело страницы создано" : "тело страницы отсутствует"); </script> </head> <body> <script> alert(document.body ? "тело страницы создано" : "тело страницы отсутствует"); </script> </body> </html> |
Цитата:
|
Цитата:
|
Цитата:
|
NovichokJS,
<!DOCTYPE html> <html> <head> <title>Untitled</title> <meta charset="utf-8"> <style type="text/css"> ul { list-style: none; width: 240px; } .list__item_done { background-image: -webkit-linear-gradient(left, #0000CD, #FF0000); background-image: linear-gradient(to right, #0000CD, #FF0000); color: #FFFFFF; } </style> <script> document.addEventListener("DOMContentLoaded", function() { const ul = document.querySelector('.list'); const lis = Array.from(ul.querySelectorAll('.list__item')); ul.addEventListener('click', () => { ul.append(...lis); for (let li of lis) { if (li.querySelector(":checked")) { li.classList.add("list__item_done"); ul.append(li) } else { li.classList.remove("list__item_done") } } }); }) </script> </head> <body> <ul class="list"> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Buy milk</li> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Pick up Tom from airport</li> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Visit party</li> </ul> </body> </html> |
:write: :lol:
<!DOCTYPE html> <html> <head> <title>Untitled</title> <meta charset="utf-8"> <style type="text/css"> ul { list-style: none; width: 240px; } .list__item_done { background-image: -webkit-linear-gradient(left, #0000CD, #FF0000); background-image: linear-gradient(to right, #0000CD, #FF0000); color: #FFFFFF; } </style> <script> document.addEventListener("DOMContentLoaded", function() { const ul = document.querySelector('.list'); const lis = Array.from(ul.querySelectorAll('.list__item')); ul.addEventListener('click', () => { const before = [], after = []; for (let li of lis) { if (li.querySelector(":checked")) { li.classList.add("list__item_done"); after.push(li) } else { li.classList.remove("list__item_done"); before.push(li) } }; ul.append(...before, ...after) }); }) </script> </head> <body> <ul class="list"> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Buy milk</li> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Pick up Tom from airport</li> <li class="list__item"><input type="checkbox" class="list__item-checkbox">Visit party</li> </ul> </body> </html> |
Цитата:
|
Цитата:
|
еще такой вот момент))
я написал костыль выше в коде у себя. Ну собственно сам массив задач: const tasks = [ { text: 'Buy milk', done: false }, { text: 'Pick up Tom from airport', done: false }, { text: 'Visit party', done: false }, { text: 'Visit doctor', done: true }, { text: 'Buy meat', done: true }, ]; И костыль, с помощью которого добавляю таски: const handlerButton = () => { const getTask = document.querySelector('.task-input'); if (getTask.value !== '') { tasks.push({ text: getTask.value, done: false }); const getListElem = document.querySelector('.list'); const getListItemElem = document.createElement('li'); getListItemElem.classList.add('list__item'); getListItemElem.innerText = getTask.value; const getCheckboxElem = document.createElement('input'); getCheckboxElem.setAttribute('type', 'checkbox'); getCheckboxElem.classList.add('list__item-checkbox'); getListElem.prepend(getListItemElem); getListItemElem.prepend(getCheckboxElem); getTask.value = ''; } }; clickButton.addEventListener('click', handlerButton); clickButton.addEventListener('click', handlerButton); const ulElement = document.querySelector('.list'); const lis = ulElement.querySelectorAll('.list__item'); const handlerChexbox = () => { for (let i = 0; i < lis.length; i++) { let li = lis[i]; if (li.querySelector(':checked')) { li.classList.add('list__item_done'); ulElement.append(li); } else { li.classList.remove('list__item_done'); } } }; ulElement.addEventListener('click', handlerChexbox); Оно работает, но не полностью. Мне надо чтобы добавленные таски также при отметке чекбокса спускались вниз. Сейчас они не добавляют класс list__item_done и не спускаются у меня. ![]() Собственно, как и куда привязать блоки кода чтобы работало опускание отмеченных чекбоксом тасков вниз? |
Цитата:
|
Цитата:
const tasks = [ { text: 'Buy milk', done: false }, { text: 'Pick up Tom from airport', done: false }, { text: 'Visit party', done: false }, { text: 'Visit doctor', done: true }, { text: 'Buy meat', done: true }, ]; const listElem = document.querySelector('.list'); const clickButton = document.querySelector('.create-task-btn'); const handlerButton = () => { const getTask = document.querySelector('.task-input'); if (getTask.value !== '') { tasks.push({ text: getTask.value, done: false }); console.log(tasks); const getListItemElem = document.createElement('li'); getListItemElem.classList.add('list__item'); getListItemElem.innerText = getTask.value; const getCheckboxElem = document.createElement('input'); getCheckboxElem.setAttribute('type', 'checkbox'); getCheckboxElem.classList.add('list__item-checkbox'); listElem.prepend(getListItemElem); getListItemElem.prepend(getCheckboxElem); getTask.value = ''; } }; clickButton.addEventListener('click', handlerButton); const handlerChexbox = () => { const lis = Array.from(listElem.querySelectorAll('.list__item')); listElem.addEventListener('click', () => { const before = [], after = []; for (let li of lis) { if (li.querySelector(':checked')) { li.classList.add('list__item_done'); after.push(li); } else { li.classList.remove('list__item_done'); before.push(li); } } listElem.append(...before, ...after); }); }; listElem.addEventListener('click', handlerChexbox); |
и это мне понравилось еще :lol: :
NovichokJS Кандидат Javascript-наук Карма: +12 |
Рони, у меня уже получилось всё синхронизировать и теперь работает как надо, спасибо!!!
|
NovichokJS,
делайте полноценные примеры, и менять надо только состояние const tasks, остальное всё лучше перенести в render |
Цитата:
касательно этого "менять надо только состояние const tasks, остальное всё лучше перенести в render" - помогите пожалуйста. Сейчас функционально то работает. Но понятно, что нужно улучшить код, рефакторинг...Вот весь итоговый код: <body> <h1 class="title">Todo List</h1> <main class="todo-list"> <div class="actions"> <input class="task-input" type="text" /> <button class="btn create-task-btn">Create</button> </div> <ul class="list"></ul> </main> <script src="index.js"></script> </body> const tasks = [ { text: 'Buy milk', done: false }, { text: 'Pick up Tom from airport', done: false }, { text: 'Visit party', done: false }, { text: 'Visit doctor', done: true }, { text: 'Buy meat', done: true }, ]; const listElem = document.querySelector('.list'); const renderTasks = tasksList => { const listItemsElems = tasksList .sort((a, b) => a.done - b.done) .map(({ text, done }) => { const listItemElem = document.createElement('li'); listItemElem.classList.add('list__item'); if (done) { listItemElem.classList.add('list__item_done'); } const checkboxElem = document.createElement('input'); checkboxElem.setAttribute('type', 'checkbox'); checkboxElem.checked = done; checkboxElem.classList.add('list__item-checkbox'); listItemElem.append(checkboxElem, text); return listItemElem; }); listElem.append(...listItemsElems); }; renderTasks(tasks); const clickButton = document.querySelector('.create-task-btn'); const handlerButton = () => { const getTask = document.querySelector('.task-input'); if (getTask.value !== '') { tasks.push({ text: getTask.value, done: false }); const getListItemElem = document.createElement('li'); getListItemElem.classList.add('list__item'); getListItemElem.innerText = getTask.value; const getCheckboxElem = document.createElement('input'); getCheckboxElem.setAttribute('type', 'checkbox'); getCheckboxElem.classList.add('list__item-checkbox'); listElem.prepend(getListItemElem); getListItemElem.prepend(getCheckboxElem); getTask.value = ''; } }; clickButton.addEventListener('click', handlerButton); const handlerChexbox = () => { const lis = Array.from(listElem.querySelectorAll('.list__item')); const before = [], after = []; for (let li of lis) { if (li.querySelector(':checked')) { li.classList.add('list__item_done'); after.push(li); } else { li.classList.remove('list__item_done'); before.push(li); } } listElem.append(...before, ...after); }; listElem.addEventListener('click', handlerChexbox); Как привести к такому порядку: при добавлении / изменении задачи - сначало добавить бы / обновить соответствующий элемент в массиве, где хранятся таски. После этого, заново отрисовать весь список в соответствии с обновленным массивом - вызов функции render. |
NovichokJS,
<!DOCTYPE html> <html> <head> <title>Untitled</title> <meta charset="utf-8"> </head> <body> <h1 class="title">Todo List</h1> <main class="todo-list"> <div class="actions"> <input class="task-input" type="text" /> <button class="btn create-task-btn">Create</button> </div> <ul class="list"></ul> </main> <script> const tasks = [{ text: 'Buy milk', done: false }, { text: 'Pick up Tom from airport', done: false }, { text: 'Visit party', done: false }, { text: 'Visit doctor', done: true }, { text: 'Buy meat', done: true }, ]; const listElem = document.querySelector('.list'); const renderTasks = tasksList => { const listItemsElems = tasksList .sort((a, b) => a.done - b.done || (a.text > b.text ? 1 : -1)) .map(({ text, done }, i) => { const listItemElem = document.createElement('li'); listItemElem.classList.add('list__item'); if (done) { listItemElem.classList.add('list__item_done'); } const checkboxElem = document.createElement('input'); checkboxElem.setAttribute('type', 'checkbox'); checkboxElem.checked = done; checkboxElem.dataset.i = i; checkboxElem.classList.add('list__item-checkbox'); listItemElem.append(checkboxElem, text); return listItemElem; }); listElem.innerHTML = ''; listElem.append(...listItemsElems); }; renderTasks(tasks); const clickButton = document.querySelector('.create-task-btn'); const handlerButton = () => { const getTask = document.querySelector('.task-input'); let text = getTask.value.trim(); if (text) { tasks.push({ text, done: false }); getTask.value = ''; renderTasks(tasks); } }; clickButton.addEventListener('click', handlerButton); const handlerChexbox = ({ target: { dataset: { i } } }) => { tasks[i].done = !tasks[i].done; renderTasks(tasks); }; listElem.addEventListener('change', handlerChexbox); </script> </body> </html> |
спасибо, круто!
|
правда вот только не понял вообще что тут происходит:
const handlerChexbox = ({ target: { dataset: { i } } }) => { tasks[i].done = !tasks[i].done; renderTasks(tasks); }; |
NovichokJS,
при формировании checkbox записывается его индекс в dataset. строка 54 checkboxElem.dataset.i = i; когда происходит изменение этого элемента в listElem. строка 84 listElem.addEventListener('change', handlerChexbox); этот индекс извлекается из dataset, находится элемент массива (объект) с таким же индексом и в этом объекте изменяется свойство done, на противоположное, было false, станет true и наоборот. |
NovichokJS,
тоже самое ... const handlerChexbox = (event) => { let target = event.target; let i = target.dataset.i; let obj = tasks[i]; if(obj.done === true) obj.done = false; else obj.done = true; renderTasks(tasks); }; |
теперь понял, спасибо!
|
последнее, хотел бы такой момент еще пофиксить - в dataset.i получаю сейчас строку, а в массиве ищу по индексу (число). Как это исправить?
|
Цитата:
|
Цитата:
![]() |
Цитата:
но есть тест let i = "3"; alert([{},{},{},{done: 45}][i].done); |
NovichokJS,
что не так? <!DOCTYPE html> <html> <head> <title>Untitled</title> <meta charset="utf-8"> </head> <body> <h1 class="title">Todo List</h1> <main class="todo-list"> <div class="actions"> <input class="task-input" type="text" /> <button class="btn create-task-btn">Create</button> </div> <ul class="list"></ul> </main> <script> const tasks = [{ text: 'Buy milk', done: false }, { text: 'Pick up Tom from airport', done: false }, { text: 'Visit party', done: false }, { text: 'Visit doctor', done: true }, { text: 'Buy meat', done: true }, ]; const listElem = document.querySelector('.list'); const renderTasks = tasksList => { const listItemsElems = tasksList .sort((a, b) => a.done - b.done || (a.text > b.text ? 1 : -1)) .map(({ text, done }, i) => { const listItemElem = document.createElement('li'); listItemElem.classList.add('list__item'); if (done) { listItemElem.classList.add('list__item_done'); } const checkboxElem = document.createElement('input'); checkboxElem.setAttribute('type', 'checkbox'); checkboxElem.checked = done; checkboxElem.dataset.i = i; checkboxElem.classList.add('list__item-checkbox'); listItemElem.append(checkboxElem, text); return listItemElem; }); listElem.innerHTML = ''; listElem.append(...listItemsElems); }; renderTasks(tasks); const clickButton = document.querySelector('.create-task-btn'); const handlerButton = () => { const getTask = document.querySelector('.task-input'); let text = getTask.value.trim(); if (text) { tasks.push({ text, done: false }); getTask.value = ''; renderTasks(tasks); } }; clickButton.addEventListener('click', handlerButton); const handlerChexbox = (event) => { let target = event.target; let i = target.dataset.i; let obj = tasks[i]; if(obj.done === true) obj.done = false; else obj.done = true; renderTasks(tasks); }; listElem.addEventListener('change', handlerChexbox); </script> </body> </html> |
Часовой пояс GMT +3, время: 00:31. |