Изменение поведения выбранных чекбоксов
У меня есть список 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, время: 05:48. |