Uncaught TypeError: Cannot read property ‘contains’ of undefined
Uncaught TypeError: Cannot set property ‘display’ of undefined
I am trying to loop through todoList and get the child element. Where I am wrong? The child element is the list item. The list items are dynamically added on adding a todo.
JavaScript
x
61
61
1
const todoInput = document.querySelector('.todo-input');
2
const todoList = document.querySelector('.todo-list');
3
const filterOption = document.querySelector(".filter-todo");
4
const todoButton = document.querySelector(".todo-button");
5
6
todoButton.addEventListener("click", addTodo);
7
filterOption.addEventListener("click", filterTodo);
8
9
function addTodo(e) {
10
e.preventDefault();
11
console.log("hello");
12
//todo div
13
const todoDiv = document.createElement("div");
14
todoDiv.classList.add("todo");
15
//create li
16
const newTodo = document.createElement('li');
17
newTodo.innerText = todoInput.value;
18
newTodo.classList.add('todo-item')
19
todoDiv.appendChild(newTodo);
20
//check mark button
21
const completedButton = document.createElement('button');
22
completedButton.innerHTML = '<i class="fas fa-check"></i>';
23
completedButton.classList.add("complete-btn");
24
todoDiv.appendChild(completedButton);
25
//check trash button
26
const trashButton = document.createElement('button');
27
trashButton.innerHTML = '<i class="fas fa-trash"></i>';
28
trashButton.classList.add("trash-btn");
29
todoDiv.appendChild(trashButton);
30
31
//append to list
32
todoList.appendChild(todoDiv)
33
//clear todo input value
34
todoInput.value = "";
35
36
}
37
38
function filterTodo(e) {
39
const todos = todoList.childNodes;
40
todos.forEach(function(todo) {
41
console.log(todo);
42
switch (e.target.value) {
43
case "all":
44
todo.style.display = "flex";
45
break;
46
case "completed":
47
if (todo.classList.contains("completed")) {
48
todo.style.display = "flex";
49
} else {
50
todo.style.display = "none";
51
}
52
break;
53
case "uncompleted":
54
if (!todo.classList.contains("completed")) {
55
todo.style.display = "flex";
56
} else {
57
todo.style.display = "none";
58
}
59
}
60
});
61
}
JavaScript
1
95
95
1
.todo-container {
2
display: flex;
3
justify-content: center;
4
align-items: center;
5
}
6
7
.todo-list {
8
min-width: 30%;
9
list-style: none;
10
}
11
12
.todo {
13
margin: 0.5rem;
14
background: white;
15
color: black;
16
font-size: 1.5rem;
17
display: flex;
18
justify-content: space-between;
19
align-items: center;
20
transition: all 0.5s ease;
21
}
22
23
.todo li {
24
flex: 1;
25
}
26
27
.trash-btn,
28
.complete-btn {
29
background: #ff6f47;
30
color: white;
31
border: none;
32
padding: 1rem;
33
cursor: pointer;
34
font-size: 1rem;
35
}
36
37
.complete-btn {
38
background: rgb(73, 204, 73);
39
}
40
41
.todo-item {
42
padding: 0rem 0.5rem;
43
}
44
45
.fa-trash,
46
.fa-check {
47
pointer-events: none;
48
}
49
50
.completed {
51
text-decoration: line-through;
52
opacity: 0.5;
53
}
54
55
.fall {
56
transform: translateY(8rem) rotateZ(20deg);
57
opacity: 0;
58
}
59
60
select {
61
-webkit-appearance: none;
62
-moz-appearance: none;
63
appearance: none;
64
outline: none;
65
border: none;
66
}
67
68
.select {
69
margin: 1rem;
70
position: relative;
71
overflow: hidden;
72
}
73
74
select {
75
color: #ff6f47;
76
width: 10rem;
77
cursor: pointer;
78
padding: 1rem;
79
}
80
81
.select::after {
82
content: "25BC";
83
position: absolute;
84
background: #ff6f47;
85
top: 0;
86
right: 0;
87
padding: 1rem;
88
pointer-events: none;
89
transition: all 0.3s ease;
90
}
91
92
.select:hover::after {
93
background: white;
94
color: #ff6f47;
95
}
JavaScript
1
19
19
1
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" />
2
<form>
3
<input type="text" class="todo-input">
4
<button class="todo-button" type="submit">
5
<i class="fas fa-plus-square"></i>
6
</button>
7
<div class="select">
8
<select name="todos" class="filter-todo">
9
<option value="all">All</option>
10
<option value="completed">Completed</option>
11
<option value="uncompleted">Uncompleted</option>
12
</select>
13
</div>
14
</form>
15
<div class="todo-container">
16
<ul class="todo-list">
17
<!---Adding todos dynamically-->
18
</ul>
19
</div>
Advertisement
Answer
Quite a bit of stuff to rewrite
I added the completed and delete functionality
JavaScript
1
60
60
1
const todoInput = document.querySelector('.todo-input');
2
const todoList = document.querySelector('.todo-list');
3
const filterOption = document.querySelector(".filter-todo");
4
const todoButton = document.querySelector(".todo-button");
5
6
todoButton.addEventListener("click", addTodo);
7
filterOption.addEventListener("change", filterTodo);
8
todoList.addEventListener("click", handleTodo)
9
10
function handleTodo(e) {
11
const tgt = e.target.closest("button");
12
if (tgt) {
13
if (tgt.classList.contains("complete-btn")) {
14
tgt.closest("div").classList.add("completed");
15
} else if (tgt.classList.contains("trash-btn")) {
16
tgt.closest("div").remove();
17
}
18
}
19
}
20
21
function addTodo(e) {
22
e.preventDefault();
23
console.log("hello");
24
//todo div
25
const todoDiv = document.createElement("div");
26
todoDiv.classList.add("todo");
27
//create li
28
const newTodo = document.createElement('li');
29
newTodo.innerText = todoInput.value;
30
newTodo.classList.add('todo-item')
31
todoDiv.appendChild(newTodo);
32
//check mark button
33
const completedButton = document.createElement('button');
34
completedButton.innerHTML = '<i class="fas fa-check"></i>';
35
completedButton.classList.add("complete-btn");
36
todoDiv.appendChild(completedButton);
37
//check trash button
38
const trashButton = document.createElement('button');
39
trashButton.innerHTML = '<i class="fas fa-trash"></i>';
40
trashButton.classList.add("trash-btn");
41
todoDiv.appendChild(trashButton);
42
43
//append to list
44
todoList.appendChild(todoDiv)
45
//clear todo input value
46
todoInput.value = "";
47
48
}
49
50
function filterTodo(e) {
51
const todos = todoList.querySelectorAll(".todo-list div");
52
const val = e.target.value;
53
todos.forEach(function(todo) {
54
const show = val === "all" ||
55
(val === "completed" && todo.classList.contains("completed")) ||
56
(val === "uncompleted" && !todo.classList.contains("completed"));
57
todo.classList.toggle("hide", !show)
58
59
});
60
}
JavaScript
1
99
99
1
.todo-container {
2
display: flex;
3
justify-content: center;
4
align-items: center;
5
}
6
7
.todo-list {
8
min-width: 30%;
9
list-style: none;
10
}
11
12
.todo {
13
margin: 0.5rem;
14
background: white;
15
color: black;
16
font-size: 1.5rem;
17
display: flex;
18
justify-content: space-between;
19
align-items: center;
20
transition: all 0.5s ease;
21
}
22
23
.todo li {
24
flex: 1;
25
}
26
27
.trash-btn,
28
.complete-btn {
29
background: #ff6f47;
30
color: white;
31
border: none;
32
padding: 1rem;
33
cursor: pointer;
34
font-size: 1rem;
35
}
36
37
.complete-btn {
38
background: rgb(73, 204, 73);
39
}
40
41
.todo-item {
42
padding: 0rem 0.5rem;
43
}
44
45
.fa-trash,
46
.fa-check {
47
pointer-events: none;
48
}
49
50
.completed {
51
text-decoration: line-through;
52
opacity: 0.5;
53
}
54
55
.fall {
56
transform: translateY(8rem) rotateZ(20deg);
57
opacity: 0;
58
}
59
60
select {
61
-webkit-appearance: none;
62
-moz-appearance: none;
63
appearance: none;
64
outline: none;
65
border: none;
66
}
67
68
.select {
69
margin: 1rem;
70
position: relative;
71
overflow: hidden;
72
}
73
74
select {
75
color: #ff6f47;
76
width: 10rem;
77
cursor: pointer;
78
padding: 1rem;
79
}
80
81
.select::after {
82
content: "25BC";
83
position: absolute;
84
background: #ff6f47;
85
top: 0;
86
right: 0;
87
padding: 1rem;
88
pointer-events: none;
89
transition: all 0.3s ease;
90
}
91
92
.select:hover::after {
93
background: white;
94
color: #ff6f47;
95
}
96
97
.hide {
98
display: none
99
}
JavaScript
1
20
20
1
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" />
2
3
<form>
4
<input type="text" class="todo-input">
5
<button class="todo-button" type="submit">
6
<i class="fas fa-plus-square"></i>
7
</button>
8
<div class="select">
9
<select name="todos" class="filter-todo">
10
<option value="all">All</option>
11
<option value="completed">Completed</option>
12
<option value="uncompleted">Uncompleted</option>
13
</select>
14
</div>
15
</form>
16
<div class="todo-container">
17
<ul class="todo-list">
18
<!---Adding todos dynamically-->
19
</ul>
20
</div>