From 9d0e1be1c2fe99bb7fcea59c7b6f5dcdc1ac4316 Mon Sep 17 00:00:00 2001 From: JiEun Lee Date: Mon, 12 Jul 2021 17:16:40 +0900 Subject: [PATCH 01/12] =?UTF-8?q?feat:=20app.js=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 1 + src/app.js | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 src/app.js diff --git a/index.html b/index.html index 13a02fdb..18d411b0 100644 --- a/index.html +++ b/index.html @@ -5,6 +5,7 @@ 이벤트 - TODOS +
diff --git a/src/app.js b/src/app.js new file mode 100644 index 00000000..c256c268 --- /dev/null +++ b/src/app.js @@ -0,0 +1,5 @@ +import TodoApp from './components/TodoApp.js'; + +window.addEventListener('DOMContentLoaded', () => { + const todoApp = new TodoApp(); +}); From b0b3d0f0dcc013b27d3f1a1fd123f74ca8240bd6 Mon Sep 17 00:00:00 2001 From: JiEun Lee Date: Mon, 12 Jul 2021 17:21:59 +0900 Subject: [PATCH 02/12] =?UTF-8?q?feat:=20TodoInput=20Add=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/TodoApp.js | 23 +++++++++++++++++++++++ src/components/TodoInput.js | 14 ++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 src/components/TodoApp.js create mode 100644 src/components/TodoInput.js diff --git a/src/components/TodoApp.js b/src/components/TodoApp.js new file mode 100644 index 00000000..6813cf1c --- /dev/null +++ b/src/components/TodoApp.js @@ -0,0 +1,23 @@ +import TodoItem from './TodoItem.js'; +import TodoInput from './TodoInput.js'; +import TodoList from './TodoList.js'; +import TodoCount from './TodoCount.js'; +import { TodoFilter, FilterType } from './TodoFilter.js'; + +export default function TodoApp() { + let id = 0; + this.todoItems = []; + + this.setState = (updatedItems) => { + this.todoItems = updatedItems; + todoList.setState(this.todoItems); + }; + + new TodoInput({ + onAdd: (contents) => { + const newTodoItem = new TodoItem(contents, ++id); + this.todoItems.push(newTodoItem); + this.setState(this.todoItems); + }, + }); +} diff --git a/src/components/TodoInput.js b/src/components/TodoInput.js new file mode 100644 index 00000000..472758c8 --- /dev/null +++ b/src/components/TodoInput.js @@ -0,0 +1,14 @@ +// 입력받는 컴포넌트 +export default function TodoInput({ onAdd }) { + const todoInput = document.querySelector('#new-todo-title'); + + todoInput.addEventListener('keydown', (event) => this.addTodoItem(event)); + + this.addTodoItem = (event) => { + if (event.key === 'Enter') { + const newTodoTarget = event.target; + onAdd(newTodoTarget.value); + newTodoTarget.value = ''; + } + }; +} From 15279996c8b0865f2c176c4e8b0d8cbaccc108df Mon Sep 17 00:00:00 2001 From: JiEun Lee Date: Mon, 12 Jul 2021 17:26:10 +0900 Subject: [PATCH 03/12] =?UTF-8?q?feat:=20TodoItem=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/TodoItem.js | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/components/TodoItem.js diff --git a/src/components/TodoItem.js b/src/components/TodoItem.js new file mode 100644 index 00000000..d462363d --- /dev/null +++ b/src/components/TodoItem.js @@ -0,0 +1,8 @@ +export default class TodoItem { + constructor(contents, id) { + this.id = id; + this.contents = contents; + this.completed = false; + this.editing = false; + } +} From 78984e1e5a47f415caed47556b0e720c9eaddfb7 Mon Sep 17 00:00:00 2001 From: JiEun Lee Date: Mon, 12 Jul 2021 17:27:24 +0900 Subject: [PATCH 04/12] =?UTF-8?q?feat:=20TodoList=20Delete,=20Completed,?= =?UTF-8?q?=20Editing,=20Edit=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/TodoApp.js | 48 +++++++++++++++++++++++++++++++++++ src/components/TodoList.js | 52 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 src/components/TodoList.js diff --git a/src/components/TodoApp.js b/src/components/TodoApp.js index 6813cf1c..e56e4b04 100644 --- a/src/components/TodoApp.js +++ b/src/components/TodoApp.js @@ -20,4 +20,52 @@ export default function TodoApp() { this.setState(this.todoItems); }, }); + + const todoList = new TodoList({ + onEditing: (id) => { + this.todoItems = this.todoItems.map((item) => { + if (item.id === id) { + item.editing = !item.editing; + } + return item; + }); + todoList.setState(this.todoItems); + }, + onComplete: (id) => { + this.todoItems = this.todoItems.map((item) => { + if (item.id === id) { + item.completed = !item.completed; + } + return item; + }); + todoList.setState(this.todoItems); + }, + onDelete: (id) => { + this.todoItems = this.todoItems.filter((item) => { + return item.id !== id; + }); + todoList.setState(this.todoItems); + }, + onEdit: (e, id) => { + if (e.key === 'Enter') { + this.todoItems = this.todoItems.map((item) => { + if (item.id === id) { + item.contents = e.target.value; + item.editing = false; + } + return item; + }); + todoList.setState(this.todoItems); + } + if (e.key === 'Escape') { + this.todoItems = this.todoItems.map((item) => { + if (item.id === id) { + item.editing = false; + } + return item; + }); + todoList.setState(this.todoItems); + } + }, + }); } diff --git a/src/components/TodoList.js b/src/components/TodoList.js new file mode 100644 index 00000000..d819b584 --- /dev/null +++ b/src/components/TodoList.js @@ -0,0 +1,52 @@ +// todoList 보여주는 컴포넌트 +export default function TodoList({ onComplete, onDelete, onEditing, onEdit }) { + this.todoList = document.querySelector('#todo-list'); + + this.setState = (updatedTodoItems) => { + this.todoItems = updatedTodoItems; + this.render(this.todoItems); + }; + + this.todoList.addEventListener('click', (event) => { + const li = event.target.parentNode.parentNode; + const id = parseInt(li.dataset.id); + if (event.target.className === 'toggle') { + onComplete(id); + } + if (event.target.className === 'destroy') { + onDelete(id); + } + }); + + this.todoList.addEventListener('dblclick', (event) => { + const li = event.target.parentNode.parentNode; + const id = parseInt(li.dataset.id); + onEditing(id); + }); + + this.todoList.addEventListener('keydown', (event) => { + const li = event.target.parentNode; + const id = parseInt(li.dataset.id); + onEdit(event, id); + }); + + this.render = (items) => { + const template = items.map((item) => { + return ` +
  • +
    + + + +
    + +
  • + `; + }); + this.todoList.innerHTML = template.join(''); + }; +} From fe59829ba31eaaee49c02945697f494cf34c74b0 Mon Sep 17 00:00:00 2001 From: JiEun Lee Date: Mon, 12 Jul 2021 17:28:29 +0900 Subject: [PATCH 05/12] =?UTF-8?q?feat:=20TodoCount=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/TodoApp.js | 6 ++++++ src/components/TodoCount.js | 7 +++++++ 2 files changed, 13 insertions(+) create mode 100644 src/components/TodoCount.js diff --git a/src/components/TodoApp.js b/src/components/TodoApp.js index e56e4b04..20d0fb62 100644 --- a/src/components/TodoApp.js +++ b/src/components/TodoApp.js @@ -18,6 +18,7 @@ export default function TodoApp() { const newTodoItem = new TodoItem(contents, ++id); this.todoItems.push(newTodoItem); this.setState(this.todoItems); + todoCount.setState(this.todoItems); }, }); @@ -30,6 +31,7 @@ export default function TodoApp() { return item; }); todoList.setState(this.todoItems); + todoCount.setState(this.todoItems); }, onComplete: (id) => { this.todoItems = this.todoItems.map((item) => { @@ -39,12 +41,14 @@ export default function TodoApp() { return item; }); todoList.setState(this.todoItems); + todoCount.setState(this.todoItems); }, onDelete: (id) => { this.todoItems = this.todoItems.filter((item) => { return item.id !== id; }); todoList.setState(this.todoItems); + todoCount.setState(this.todoItems); }, onEdit: (e, id) => { if (e.key === 'Enter') { @@ -56,6 +60,7 @@ export default function TodoApp() { return item; }); todoList.setState(this.todoItems); + todoCount.setState(this.todoItems); } if (e.key === 'Escape') { this.todoItems = this.todoItems.map((item) => { @@ -65,6 +70,7 @@ export default function TodoApp() { return item; }); todoList.setState(this.todoItems); + todoCount.setState(this.todoItems); } }, }); diff --git a/src/components/TodoCount.js b/src/components/TodoCount.js new file mode 100644 index 00000000..b836146a --- /dev/null +++ b/src/components/TodoCount.js @@ -0,0 +1,7 @@ +export default function TodoCount() { + this.todoCount = document.querySelector('.todo-count strong'); + + this.setState = (todoItems) => { + this.todoCount.textContent = todoItems.length; + }; +} From ec7652267353144bacff6aa8c1aa36e716623ade Mon Sep 17 00:00:00 2001 From: JiEun Lee Date: Mon, 12 Jul 2021 17:30:11 +0900 Subject: [PATCH 06/12] =?UTF-8?q?feat:=20TodoFilter=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/TodoApp.js | 28 ++++++++++++++++++++++++++++ src/components/TodoFilter.js | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 src/components/TodoFilter.js diff --git a/src/components/TodoApp.js b/src/components/TodoApp.js index 20d0fb62..858e6bf6 100644 --- a/src/components/TodoApp.js +++ b/src/components/TodoApp.js @@ -13,6 +13,8 @@ export default function TodoApp() { todoList.setState(this.todoItems); }; + const todoCount = new TodoCount(); + new TodoInput({ onAdd: (contents) => { const newTodoItem = new TodoItem(contents, ++id); @@ -74,4 +76,30 @@ export default function TodoApp() { } }, }); + + new TodoFilter({ + filtering: (type) => { + if (type === FilterType.all) { + todoList.setState(this.todoItems); + todoCount.setState(this.todoItems); + return; + } + if (type === FilterType.active) { + const activeItems = this.todoItems.filter((item) => { + return item.completed === false; + }); + todoList.setState(activeItems); + todoCount.setState(activeItems); + return; + } + if (type === FilterType.completed) { + const completedItems = this.todoItems.filter((item) => { + return item.completed === true; + }); + todoList.setState(completedItems); + todoCount.setState(completedItems); + return; + } + }, + }); } diff --git a/src/components/TodoFilter.js b/src/components/TodoFilter.js new file mode 100644 index 00000000..f6ba0a1a --- /dev/null +++ b/src/components/TodoFilter.js @@ -0,0 +1,36 @@ +export const FilterType = Object.freeze({ + all: 'all', + active: 'active', + completed: 'completed', +}); + +export function TodoFilter({ filtering }) { + this.filters = document.querySelector('.filters'); + this.filtersBtn = this.filters.querySelectorAll('a'); + + this.filters.addEventListener('click', (event) => this.onClick(event)); + + this.onClick = (event) => { + const target = event.target; + const filterType = target.className; + + // selected class 제거 + this.removeSelectedClass(); + // 선택한 filter에 selected class 추가 + this.addSelectedClass(target); + + filtering(filterType); + }; + + this.removeSelectedClass = () => { + this.filtersBtn.forEach((item) => { + if (item.classList.contains('selected')) { + item.classList.remove('selected'); + } + }); + }; + + this.addSelectedClass = (target) => { + target.classList.add('selected'); + }; +} From a6a8d2ed7541ac5b599c8d3180c77945e76847fe Mon Sep 17 00:00:00 2001 From: JiEun Lee Date: Mon, 12 Jul 2021 17:31:48 +0900 Subject: [PATCH 07/12] =?UTF-8?q?feat:=20localStorage=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?,=20CRUD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.js | 1 + src/components/TodoApp.js | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/app.js b/src/app.js index c256c268..818a740a 100644 --- a/src/app.js +++ b/src/app.js @@ -2,4 +2,5 @@ import TodoApp from './components/TodoApp.js'; window.addEventListener('DOMContentLoaded', () => { const todoApp = new TodoApp(); + todoApp.init(); }); diff --git a/src/components/TodoApp.js b/src/components/TodoApp.js index 858e6bf6..f2e4fa98 100644 --- a/src/components/TodoApp.js +++ b/src/components/TodoApp.js @@ -5,9 +5,26 @@ import TodoCount from './TodoCount.js'; import { TodoFilter, FilterType } from './TodoFilter.js'; export default function TodoApp() { + const localStorageKey = 'TODOS'; let id = 0; this.todoItems = []; + this.init = () => { + const savedItems = localStorage.getItem(localStorageKey); + if (savedItems) { + const parsedItems = JSON.parse(localStorage.getItem(localStorageKey)); + this.todoItems = parsedItems ? parsedItems : []; + id = parsedItems ? parsedItems.length : 0; + + todoList.setState(parsedItems); + todoCount.setState(parsedItems); + } + }; + + const saveItems = () => { + localStorage.setItem(localStorageKey, JSON.stringify(this.todoItems)); + }; + this.setState = (updatedItems) => { this.todoItems = updatedItems; todoList.setState(this.todoItems); @@ -21,6 +38,8 @@ export default function TodoApp() { this.todoItems.push(newTodoItem); this.setState(this.todoItems); todoCount.setState(this.todoItems); + + saveItems(); }, }); @@ -34,6 +53,7 @@ export default function TodoApp() { }); todoList.setState(this.todoItems); todoCount.setState(this.todoItems); + saveItems(); }, onComplete: (id) => { this.todoItems = this.todoItems.map((item) => { @@ -44,6 +64,7 @@ export default function TodoApp() { }); todoList.setState(this.todoItems); todoCount.setState(this.todoItems); + saveItems(); }, onDelete: (id) => { this.todoItems = this.todoItems.filter((item) => { @@ -51,6 +72,7 @@ export default function TodoApp() { }); todoList.setState(this.todoItems); todoCount.setState(this.todoItems); + saveItems(); }, onEdit: (e, id) => { if (e.key === 'Enter') { @@ -63,6 +85,7 @@ export default function TodoApp() { }); todoList.setState(this.todoItems); todoCount.setState(this.todoItems); + saveItems(); } if (e.key === 'Escape') { this.todoItems = this.todoItems.map((item) => { @@ -73,6 +96,7 @@ export default function TodoApp() { }); todoList.setState(this.todoItems); todoCount.setState(this.todoItems); + saveItems(); } }, }); From 0e26126ccc35fa95ef41205230f0467d0f71f411 Mon Sep 17 00:00:00 2001 From: jieun lee Date: Mon, 12 Jul 2021 17:38:08 +0900 Subject: [PATCH 08/12] Update README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 502436de..0e28256a 100644 --- a/README.md +++ b/README.md @@ -39,15 +39,15 @@ ## 🎯 요구사항 -- [ ] todo list에 todoItem을 키보드로 입력하여 추가하기 -- [ ] todo list의 체크박스를 클릭하여 complete 상태로 변경 (li tag 에 completed class 추가, input 태그에 checked 속성 추가) -- [ ] todo list의 x버튼을 이용해서 해당 엘리먼트를 삭제 -- [ ] todo list를 더블클릭했을 때 input 모드로 변경 (li tag 에 editing class 추가) 단 이때 수정을 완료하지 않은 상태에서 esc키를 누르면 수정되지 않은 채로 다시 view 모드로 복귀 -- [ ] todo list의 item갯수를 count한 갯수를 리스트의 하단에 보여주기 -- [ ] todo list의 상태값을 확인하여, 해야할 일과, 완료한 일을 클릭하면 해당 상태의 아이템만 보여주기 +- [x] todo list에 todoItem을 키보드로 입력하여 추가하기 +- [x] todo list의 체크박스를 클릭하여 complete 상태로 변경 (li tag 에 completed class 추가, input 태그에 checked 속성 추가) +- [x] todo list의 x버튼을 이용해서 해당 엘리먼트를 삭제 +- [x] todo list를 더블클릭했을 때 input 모드로 변경 (li tag 에 editing class 추가) 단 이때 수정을 완료하지 않은 상태에서 esc키를 누르면 수정되지 않은 채로 다시 view 모드로 복귀 +- [x] todo list의 item갯수를 count한 갯수를 리스트의 하단에 보여주기 +- [x] todo list의 상태값을 확인하여, 해야할 일과, 완료한 일을 클릭하면 해당 상태의 아이템만 보여주기 ## 🎯🎯 심화 요구사항 -- [ ] localStorage에 데이터를 저장하여, TodoItem의 CRUD를 반영하기. 따라서 새로고침하여도 저장된 데이터를 확인할 수 있어야 함 +- [x] localStorage에 데이터를 저장하여, TodoItem의 CRUD를 반영하기. 따라서 새로고침하여도 저장된 데이터를 확인할 수 있어야 함
    From 1f5766e759b12be24eb2f303e34849f1d6b0d6ba Mon Sep 17 00:00:00 2001 From: JiEun Lee Date: Tue, 13 Jul 2021 12:03:57 +0900 Subject: [PATCH 09/12] =?UTF-8?q?refactor:=20LocalStorage=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/LocalStorage.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/components/LocalStorage.js diff --git a/src/components/LocalStorage.js b/src/components/LocalStorage.js new file mode 100644 index 00000000..1732f9d9 --- /dev/null +++ b/src/components/LocalStorage.js @@ -0,0 +1,13 @@ +export default class LocalStorage { + constructor(key) { + this.key = key; + } + saveItems = (todoItems) => { + localStorage.setItem(this.key, JSON.stringify(todoItems)); + }; + + getItems = () => { + const parsedData = localStorage.getItem(this.key); + return parsedData && JSON.parse(parsedData); + }; +} From 000c60119825d33576c4d03759eb28d5153e42da Mon Sep 17 00:00:00 2001 From: JiEun Lee Date: Tue, 13 Jul 2021 12:04:05 +0900 Subject: [PATCH 10/12] =?UTF-8?q?refactor:=20LocalStorage=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/app.js b/src/app.js index 818a740a..15afe7b6 100644 --- a/src/app.js +++ b/src/app.js @@ -1,6 +1,11 @@ import TodoApp from './components/TodoApp.js'; +import LocalStorage from './components/LocalStorage.js'; +const LS_KEY = 'TODOS'; window.addEventListener('DOMContentLoaded', () => { - const todoApp = new TodoApp(); - todoApp.init(); + const storage = new LocalStorage(LS_KEY); + const savedData = storage.getItems(); + + const todoApp = new TodoApp(storage); + todoApp.init(savedData); }); From baf0d2ee5c0c40a121894aea50efd736e5b9658a Mon Sep 17 00:00:00 2001 From: JiEun Lee Date: Tue, 13 Jul 2021 12:06:27 +0900 Subject: [PATCH 11/12] =?UTF-8?q?refactor:=20=EC=9D=B5=EB=AA=85=20?= =?UTF-8?q?=EC=BD=9C=EB=B0=B1=ED=95=A8=EC=88=98=20->=20=EA=B8=B0=EB=AA=85?= =?UTF-8?q?=20=EC=BD=9C=EB=B0=B1=ED=95=A8=EC=88=98=EB=A1=9C=20=EB=94=B0?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/TodoFilter.js | 19 ++++++------ src/components/TodoInput.js | 12 +++++--- src/components/TodoList.js | 60 ++++++++++++++++++++---------------- 3 files changed, 52 insertions(+), 39 deletions(-) diff --git a/src/components/TodoFilter.js b/src/components/TodoFilter.js index f6ba0a1a..1be34509 100644 --- a/src/components/TodoFilter.js +++ b/src/components/TodoFilter.js @@ -4,22 +4,23 @@ export const FilterType = Object.freeze({ completed: 'completed', }); -export function TodoFilter({ filtering }) { +export function TodoFilter() { this.filters = document.querySelector('.filters'); this.filtersBtn = this.filters.querySelectorAll('a'); - this.filters.addEventListener('click', (event) => this.onClick(event)); + this.filters.addEventListener('click', (event) => this.handleClick(event)); - this.onClick = (event) => { - const target = event.target; - const filterType = target.className; + this.setEventListener = (onFilter) => { + this.onFilter = onFilter; + }; + + this.handleClick = (event) => { + const type = event.target.className; - // selected class 제거 this.removeSelectedClass(); - // 선택한 filter에 selected class 추가 - this.addSelectedClass(target); + this.addSelectedClass(event.target); - filtering(filterType); + this.onFilter && this.onFilter(type); }; this.removeSelectedClass = () => { diff --git a/src/components/TodoInput.js b/src/components/TodoInput.js index 472758c8..502f5d81 100644 --- a/src/components/TodoInput.js +++ b/src/components/TodoInput.js @@ -1,13 +1,17 @@ // 입력받는 컴포넌트 -export default function TodoInput({ onAdd }) { +export default function TodoInput() { const todoInput = document.querySelector('#new-todo-title'); - todoInput.addEventListener('keydown', (event) => this.addTodoItem(event)); + todoInput.addEventListener('keydown', (event) => this.handleOnAdd(event)); - this.addTodoItem = (event) => { + this.setEventListener = (onAdd) => { + this.onAdd = onAdd; + }; + + this.handleOnAdd = (event) => { if (event.key === 'Enter') { const newTodoTarget = event.target; - onAdd(newTodoTarget.value); + this.onAdd && this.onAdd(newTodoTarget.value); newTodoTarget.value = ''; } }; diff --git a/src/components/TodoList.js b/src/components/TodoList.js index d819b584..cbbc883e 100644 --- a/src/components/TodoList.js +++ b/src/components/TodoList.js @@ -1,35 +1,23 @@ // todoList 보여주는 컴포넌트 -export default function TodoList({ onComplete, onDelete, onEditing, onEdit }) { - this.todoList = document.querySelector('#todo-list'); +export default function TodoList() { + const todoList = document.querySelector('#todo-list'); + + todoList.addEventListener('click', (event) => this.handleClick(event)); + todoList.addEventListener('dblclick', (event) => this.handleDblClick(event)); + todoList.addEventListener('keydown', (event) => this.handleKeydown(event)); + + this.setEventListener = (onComplete, onDelete, onEdit, onUpdate) => { + this.onComplete = onComplete; + this.onDelete = onDelete; + this.onEdit = onEdit; + this.onUpdate = onUpdate; + }; this.setState = (updatedTodoItems) => { this.todoItems = updatedTodoItems; this.render(this.todoItems); }; - this.todoList.addEventListener('click', (event) => { - const li = event.target.parentNode.parentNode; - const id = parseInt(li.dataset.id); - if (event.target.className === 'toggle') { - onComplete(id); - } - if (event.target.className === 'destroy') { - onDelete(id); - } - }); - - this.todoList.addEventListener('dblclick', (event) => { - const li = event.target.parentNode.parentNode; - const id = parseInt(li.dataset.id); - onEditing(id); - }); - - this.todoList.addEventListener('keydown', (event) => { - const li = event.target.parentNode; - const id = parseInt(li.dataset.id); - onEdit(event, id); - }); - this.render = (items) => { const template = items.map((item) => { return ` @@ -47,6 +35,26 @@ export default function TodoList({ onComplete, onDelete, onEditing, onEdit }) { `; }); - this.todoList.innerHTML = template.join(''); + todoList.innerHTML = template.join(''); + }; + + this.handleKeydown = (event) => { + const id = parseInt(event.target.parentNode.dataset.id); + this.onUpdate && this.onUpdate(event, id); + }; + + this.handleDblClick = (event) => { + const id = parseInt(event.target.parentNode.parentNode.dataset.id); + this.onEdit && this.onEdit(id); + }; + + this.handleClick = (event) => { + const id = parseInt(event.target.parentNode.parentNode.dataset.id); + if (event.target.className === 'toggle') { + this.onComplete && this.onComplete(id); + } + if (event.target.className === 'destroy') { + this.onDelete && this.onDelete(id); + } }; } From f4b31837e1677aba8bc39aad5e70cf1f3a8c2567 Mon Sep 17 00:00:00 2001 From: JiEun Lee Date: Tue, 13 Jul 2021 12:08:21 +0900 Subject: [PATCH 12/12] =?UTF-8?q?refactor:=20=EC=A0=84=EB=B0=98=EC=A0=81?= =?UTF-8?q?=EC=9D=B8=20=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - LocalStorage 분리 - setStatus 통합 - 인수 타입을 메서드 -> 함수로 수정 --- src/components/TodoApp.js | 180 +++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 99 deletions(-) diff --git a/src/components/TodoApp.js b/src/components/TodoApp.js index f2e4fa98..205d7670 100644 --- a/src/components/TodoApp.js +++ b/src/components/TodoApp.js @@ -4,126 +4,108 @@ import TodoList from './TodoList.js'; import TodoCount from './TodoCount.js'; import { TodoFilter, FilterType } from './TodoFilter.js'; -export default function TodoApp() { - const localStorageKey = 'TODOS'; - let id = 0; +export default function TodoApp(storage) { + this.storage = storage; this.todoItems = []; + let id = 0; - this.init = () => { - const savedItems = localStorage.getItem(localStorageKey); - if (savedItems) { - const parsedItems = JSON.parse(localStorage.getItem(localStorageKey)); - this.todoItems = parsedItems ? parsedItems : []; - id = parsedItems ? parsedItems.length : 0; + this.init = (savedData) => { + this.todoItems = savedData ?? []; + id = savedData.length ?? 0; - todoList.setState(parsedItems); - todoCount.setState(parsedItems); - } + savedData && this.setState(savedData); }; - const saveItems = () => { - localStorage.setItem(localStorageKey, JSON.stringify(this.todoItems)); + this.setState = (updatedItems) => { + todoList.setState(updatedItems); + todoCount.setState(updatedItems); }; - this.setState = (updatedItems) => { - this.todoItems = updatedItems; - todoList.setState(this.todoItems); + const onAdd = (contents) => { + const newTodoItem = new TodoItem(contents, ++id); + this.todoItems.push(newTodoItem); + this.setState(this.todoItems); + this.storage.saveItems(this.todoItems); }; - const todoCount = new TodoCount(); + const onComplete = (id) => { + this.todoItems = this.todoItems.map((item) => { + if (item.id === id) { + item.completed = !item.completed; + } + return item; + }); + this.setState(this.todoItems); + this.storage.saveItems(this.todoItems); + }; - new TodoInput({ - onAdd: (contents) => { - const newTodoItem = new TodoItem(contents, ++id); - this.todoItems.push(newTodoItem); - this.setState(this.todoItems); - todoCount.setState(this.todoItems); + const onDelete = (id) => { + this.todoItems = this.todoItems.filter((item) => { + return item.id !== id; + }); + this.setState(this.todoItems); + this.storage.saveItems(this.todoItems); + }; - saveItems(); - }, - }); + const onEdit = (id) => { + this.todoItems = this.todoItems.map((item) => { + if (item.id === id) { + item.editing = !item.editing; + } + return item; + }); + this.setState(this.todoItems); + this.storage.saveItems(this.todoItems); + }; - const todoList = new TodoList({ - onEditing: (id) => { + const onUpdate = (e, id) => { + if (e.key === 'Enter') { this.todoItems = this.todoItems.map((item) => { if (item.id === id) { - item.editing = !item.editing; + item.contents = e.target.value; + item.editing = false; } return item; }); - todoList.setState(this.todoItems); - todoCount.setState(this.todoItems); - saveItems(); - }, - onComplete: (id) => { + this.setState(this.todoItems); + this.storage.saveItems(this.todoItems); + } + if (e.key === 'Escape') { this.todoItems = this.todoItems.map((item) => { if (item.id === id) { - item.completed = !item.completed; + item.editing = false; } return item; }); - todoList.setState(this.todoItems); - todoCount.setState(this.todoItems); - saveItems(); - }, - onDelete: (id) => { - this.todoItems = this.todoItems.filter((item) => { - return item.id !== id; - }); - todoList.setState(this.todoItems); - todoCount.setState(this.todoItems); - saveItems(); - }, - onEdit: (e, id) => { - if (e.key === 'Enter') { - this.todoItems = this.todoItems.map((item) => { - if (item.id === id) { - item.contents = e.target.value; - item.editing = false; - } - return item; - }); - todoList.setState(this.todoItems); - todoCount.setState(this.todoItems); - saveItems(); - } - if (e.key === 'Escape') { - this.todoItems = this.todoItems.map((item) => { - if (item.id === id) { - item.editing = false; - } - return item; - }); - todoList.setState(this.todoItems); - todoCount.setState(this.todoItems); - saveItems(); - } - }, - }); + this.setState(this.todoItems); + this.storage.saveItems(this.todoItems); + } + }; - new TodoFilter({ - filtering: (type) => { - if (type === FilterType.all) { - todoList.setState(this.todoItems); - todoCount.setState(this.todoItems); - return; - } - if (type === FilterType.active) { - const activeItems = this.todoItems.filter((item) => { - return item.completed === false; - }); - todoList.setState(activeItems); - todoCount.setState(activeItems); - return; - } - if (type === FilterType.completed) { - const completedItems = this.todoItems.filter((item) => { - return item.completed === true; - }); - todoList.setState(completedItems); - todoCount.setState(completedItems); - return; - } - }, - }); + const onFilter = (type) => { + if (type === FilterType.all) { + this.setState(this.todoItems); + } else if (type === FilterType.active) { + const activeItems = this.todoItems.filter( + (item) => item.completed === false + ); + this.setState(activeItems); + } else if (type === FilterType.completed) { + const completedItems = this.todoItems.filter( + (item) => item.completed === true + ); + this.setState(completedItems); + } + }; + + const todoInput = new TodoInput(); + todoInput.setEventListener(onAdd); + + const todoList = new TodoList(); + todoList.setEventListener(onComplete, onDelete, onEdit, onUpdate); + + const todoCount = new TodoCount(); + + const todoFilter = new TodoFilter(); + todoFilter.setEventListener(onFilter); }