TIL_171112 Todos practice

Todos Practice

v2 - without server

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Todos V2</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
<script defer src="js/app.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="title">Todos</h1>
<input id="input-todo" class="form-control input-lg" placeholder="What needs to be done?" autofocus>
<ul class="nav nav-xs nav-pills">
<li id="all" class="active">
<a>All</a>
</li>
<li id="active">
<a>Active</a>
</li>
<li id="completed">
<a>Completed</a>
</li>
</ul>
<ul id="todo-list" class="list-group">
<!-- <li class="list-group-item">
<div class="hover-anchor">
<a class="hover-action text-muted">
<span class="glyphicon glyphicon-remove-circle pull-right" data-id="1"></span>
</a>
<label class="i-checks" for="1">
<input type="checkbox" id="1" checked><i></i>
<span>Angular</span>
</label>
</div>
</li> -->
</ul>
<div class="col-xs-6">
<label class="i-checks" style="padding-left: 20px">
<input id="chk-allComplete" type="checkbox">
<i></i>
<span>Mark all as complete</span>
</label>
</div>
<div class="col-xs-6 text-right">
<button id="btn-removeCompletedTodos" class="btn btn-default btn-xs">Clear completed (
<span id="completedTodos">0</span>)</button>
<strong id="leftTodos"></strong> items left
</div>
</div>
</div>
</div>
</body>
</html>

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
(function() {
let todos;
let status = 'all';
const inputTodo = document.getElementById('input-todo');
const todoList = document.getElementById('todo-list');
const completedTodos = document.getElementById('completedTodos');
const leftTodos = document.getElementById('leftTodos');
const filterByStatus = function (){
//사용하는 값은 todo의 completed밖에 없기 때문에 distructuring
return todos.filter(( { completed } ) => {
switch (status){
case 'active' : return !completed
case 'completed' : return completed;
//all일 경우 모든 todos를 그대로 반환해야함-> filter를 거치기 위해 true로
default : return true;
}
});
};
const countCompletedTodos = function(){
return (todos.filter(( {completed} ) => completed)).length;
};
const countLeftTodos = function(){
return (todos.filter(( {completed} ) => !completed)).length;
};
const render = function() {
let html = '';
const _todos = filterByStatus();
_todos.forEach(({id, content, completed
}) => {
const checked = completed ? ' checked' : '';
html += `<li class="list-group-item">
<div class="hover-anchor">
<a class="hover-action text-muted">
<span class="glyphicon glyphicon-remove-circle pull-right" data-id="${id}"></span>
</a>
<label class="i-checks" for="${id}">
<input type="checkbox" id="${id}"${checked}><i></i>
<span>${content}</span>
</label>
</div>
</li >`;
});
completedTodos.innerHTML = countCompletedTodos();
leftTodos.innerHTML = countLeftTodos();
todoList.innerHTML = html;
};
const getTodos = function() {
todos = [
{ id: 3, content: 'HTML', completed: false },
{ id: 2, content: 'CSS', completed: true },
{ id: 1, content: 'JavaScript', completed: false }];
render();
console.log('[GET]\n', todos);
};
const lastTodoId = function() {
return todos ? Math.max(...todos.map(({id }) => id)) + 1 : 1;
};
const addTodo = function() {
const content = inputTodo.value;
inputTodo.value = '';
if (!todos || todos.length === 0) {
todos = [{ id: 1, content, completed: false }];
} else {
todos = [{id: lastTodoId(), content, completed: false}].concat(todos);
}
render();
console.log('[ADD]\n', todos);
};
const toggleTodoComplete = function(id) {
todos = todos.map(todo => (
todo.id === (+id) ? Object.assign({}, todo, {
completed: !todo.completed
}) : todo
));
render();
console.log('[TOGGLE-COMP]\n', todos);
};
const toggleTodoAllComplete = function (checked) {
todos = todos.map(({ id, content }) => ({ id, content, completed: checked }));
render();
console.log('[TOGGLE-A-COMP]\n', todos);
};
const removeTodo = function(id) {
todos = todos.filter(todo => todo.id !== (+id));
render();
console.log('[REMOVE]\n', todos);
};
const removeCompletedTodo = function(){
// filter의 리턴값을 true로 해주기위해 !completed
// completed만 쓸것이고, completed를 덮어쓰지 않을 것이기 때문에 distructuring 가능
todos = todos.filter(( { completed } ) => !completed );
render();
console.log('[RM-COMP]\n', todos);
};
inputTodo.addEventListener('keyup', (e) => {
if (e.keyCode !== 13 || inputTodo.value.trim() === '') {
return;
}
addTodo();
});
window.addEventListener('load', () => {
getTodos();
});
todoList.addEventListener('change', (e) => {
toggleTodoComplete(e.target.id);
});
todoList.addEventListener('click', ({ target }) => {
if (!target || target.nodeName !== 'SPAN' || target.parentNode.nodeName === 'LABEL') {
return;
}
removeTodo(target.dataset.id);
});
//childNode는 엔터까지 노드로 치는 반면에, children은 element요소만
// 탭 전체에서 active클래스 빼기
document.querySelector('.nav').addEventListener('click', (e) => {
if(!e.target || e.target.nodeName !== 'A') return; //방어코드
const lis = e.currentTarget.children;
[...lis].forEach((el)=>{el.classList.remove('active')
});
// 선택한 탭에만 active클래스 추가
const targetLi = e.target.parentNode;
targetLi.classList.add('active');
// 선택한 탭의 id값 가져오기
status = targetLi.id;
//console.log(status);
render();
});
document.getElementById('chk-allComplete').addEventListener('change', (e) => {
toggleTodoAllComplete(e.target.checked);
});
document.getElementById('btn-removeCompletedTodos').addEventListener('click', removeCompletedTodo);
}());