From cfe676411b2d73eb6ce61e2b1a857b189478b9c4 Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Fri, 3 Jan 2020 21:03:26 +0900 Subject: [PATCH 01/20] M2 first commit --- mission002/css/style.css | 334 +++++++++++++++++++++++++++++++++++++ mission002/index.html | 66 ++++++++ mission002/js/App.js | 80 +++++++++ mission002/js/TodoCount.js | 21 +++ mission002/js/TodoInput.js | 9 + mission002/js/TodoList.js | 91 ++++++++++ mission002/js/constant.js | 19 +++ mission002/js/index.js | 1 + 8 files changed, 621 insertions(+) create mode 100644 mission002/css/style.css create mode 100644 mission002/index.html create mode 100644 mission002/js/App.js create mode 100644 mission002/js/TodoCount.js create mode 100644 mission002/js/TodoInput.js create mode 100644 mission002/js/TodoList.js create mode 100644 mission002/js/constant.js create mode 100644 mission002/js/index.js diff --git a/mission002/css/style.css b/mission002/css/style.css new file mode 100644 index 0000000..14a905e --- /dev/null +++ b/mission002/css/style.css @@ -0,0 +1,334 @@ +html, +body { + margin: 0; + padding: 10px; +} + +button { + margin: 0; + padding: 0; + border: 0; + background: none; + font-size: 100%; + vertical-align: baseline; + font-family: inherit; + font-weight: inherit; + color: inherit; + -webkit-appearance: none; + appearance: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body { + font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; + line-height: 1.4em; + background: #f5f5f5; + color: #4d4d4d; + min-width: 230px; + max-width: 550px; + margin: 0 auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-weight: 300; +} + +:focus { + outline: 0; +} + +.hidden { + display: none; +} + +.todoapp { + background: #fff; + margin: 130px 0 40px 0; + position: relative; + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), + 0 25px 50px 0 rgba(0, 0, 0, 0.1); +} + +.todoapp input::-webkit-input-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; +} + +.todoapp h1 { + position: absolute; + top: -125px; + width: 100%; + font-size: 60px; + text-align: center; + color: dimgray; + font-weight: 100; + font-family: Helvetica Neue, Helvetica, Arial, sans-serif; +} + +.new-todo, +.edit { + position: relative; + margin: 0; + width: 100%; + font-size: 24px; + font-family: inherit; + font-weight: inherit; + line-height: 1.4em; + border: 0; + color: inherit; + padding: 6px; + box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); + box-sizing: border-box; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.new-todo { + padding: 16px 16px 16px 60px; + border: none; + background: rgba(0, 0, 0, 0.003); + box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03); +} + +.main { + position: relative; + z-index: 2; + border-top: 1px solid #e6e6e6; +} + +.toggle-all { + width: 1px; + height: 1px; + border: none; + opacity: 0; + position: absolute; + right: 100%; + bottom: 100%; +} + +.toggle-all + label { + width: 60px; + height: 34px; + font-size: 0; + position: absolute; + top: -52px; + left: -13px; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} + +.toggle-all + label:before { + content: '❯'; + font-size: 22px; + color: #e6e6e6; + padding: 10px 27px 10px 27px; +} + +.toggle-all:checked + label:before { + color: #737373; +} + +.todo-list { + margin: 0; + padding: 0; + list-style: none; +} + +.todo-list li { + position: relative; + font-size: 24px; + border-bottom: 1px solid #ededed; +} + +.todo-list li:last-child { + border-bottom: none; +} + +.todo-list li.editing { + border-bottom: none; + padding: 0; +} + +.todo-list li.editing .edit { + display: block; + width: calc(100% - 43px); + padding: 12px 16px; + margin: 0 0 0 43px; +} + +.todo-list li.editing .view { + display: none; +} + +.todo-list li .toggle { + text-align: center; + width: 40px; + height: auto; + position: absolute; + top: 0; + bottom: 0; + margin: auto 0; + border: none; + -webkit-appearance: none; + appearance: none; +} + +.todo-list li .toggle { + opacity: 0; +} + +.todo-list li .toggle + label { + background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E'); + background-repeat: no-repeat; + background-position: center left; +} + +.todo-list li .toggle:checked + label { + background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E'); +} + +.todo-list li label { + word-break: break-all; + padding: 15px 15px 15px 60px; + display: block; + line-height: 1.2; + transition: color 0.4s; +} + +.todo-list li.completed label { + color: #d9d9d9; + text-decoration: line-through; +} + +.todo-list li .destroy { + display: none; + position: absolute; + top: 0; + right: 10px; + bottom: 0; + width: 40px; + height: 40px; + margin: auto 0; + font-size: 30px; + color: #cc9a9a; + margin-bottom: 11px; + transition: color 0.2s ease-out; + cursor: pointer; +} + +.todo-list li .destroy:hover { + color: #af5b5e; +} + +.todo-list li .destroy:after { + content: '×'; +} + +.todo-list li:hover .destroy { + display: block; +} + +.todo-list li .edit { + display: none; +} + +.todo-list li.editing:last-child { + margin-bottom: -1px; +} + +.count-container { + color: #777; + padding: 10px 15px; + height: 20px; + text-align: center; + border-top: 1px solid #e6e6e6; +} + +.count-container:before { + content: ''; + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 50px; + overflow: hidden; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), + 0 8px 0 -3px #f6f6f6, + 0 9px 1px -3px rgba(0, 0, 0, 0.2), + 0 16px 0 -6px #f6f6f6, + 0 17px 2px -6px rgba(0, 0, 0, 0.2); +} + +.todo-count { + float: left; + text-align: left; +} + +.todo-count strong { + font-weight: 300; +} + +.filters { + margin: 0; + padding: 0; + list-style: none; + position: absolute; + right: 0; + left: 0; +} + +.filters li { + display: inline; +} + +.filters li a { + color: inherit; + margin: 3px; + padding: 3px 7px; + text-decoration: none; + border: 1px solid transparent; + border-radius: 3px; +} + +.filters li a:hover { + border-color: rgba(175, 47, 47, 0.1); +} + +.filters li a.selected { + border-color: rgba(175, 47, 47, 0.2); +} + +.clear-completed, html .clear-completed:active { + float: right; + position: relative; + line-height: 20px; + text-decoration: none; + cursor: pointer; +} + +.clear-completed:hover { + text-decoration: underline; +} + +.info { + margin: 65px auto 0; + color: #bfbfbf; + font-size: 10px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-align: center; +} + +.info p { + line-height: 1; +} + +.info a { + color: inherit; + text-decoration: none; + font-weight: 400; +} + +.info a:hover { + text-decoration: underline; +} diff --git a/mission002/index.html b/mission002/index.html new file mode 100644 index 0000000..6d17d43 --- /dev/null +++ b/mission002/index.html @@ -0,0 +1,66 @@ + + + + + + 이벤트 - TODOS + + + +
+
+

TODOS

+ +
+
+ +
    +
  • +
    + +
    + +
  • +
  • +
    + + + +
    + +
  • +
  • +
    + + + +
    + +
  • +
+
+
+ 0 + +
+
+ + + + + + + + diff --git a/mission002/js/App.js b/mission002/js/App.js new file mode 100644 index 0000000..cf78cf6 --- /dev/null +++ b/mission002/js/App.js @@ -0,0 +1,80 @@ +function App(data) { + this.data = data; + this.render = function (filteredData) { + todoList.setState(filteredData) + todoCount.render(filteredData) + todoCount.setState({ + totalCount: filteredData.length, + }) + } + this.setState = function (nextData) { + this.data = nextData; + todoList.setState(this.data) + todoCount.setState({ + totalCount: this.data.length, + }) + } + + const $todoList = document.querySelector('.todo-list') + const $todoFilter = document.querySelector('.filters'); + const todoList = new TodoList({ + $target: $todoList, + $targetFilter: $todoFilter, + data: this.data, + onToggleClick: (index) => { + const nextData = [...this.data] + nextData[index].isCompleted = !nextData[index].isCompleted + this.setState(nextData) + }, + onTodoEdit: (index) => { + const nextData = [...this.data] + if (!nextData[index].isCompleted) { + nextData[index].isEditing = !nextData[index].isEditing + } + this.setState(nextData) + }, + onRemoveClick: (index) => { + const nextData = [...this.data] + nextData.splice(index, 1) + this.setState(nextData) + }, + onTodoChange: (index, value) => { + const nextData = [...this.data] + nextData[index] = { + text: value, + isCompleted: false, + isEditing: false + }; + this.setState(nextData) + }, + onFilterClick: (filterBoolean) => { + let filteredData = [...this.data] + filteredData = this.data.filter(todo => todo.isCompleted !== filterBoolean) + this.render(filteredData) + } + }); + + const $todoCount = document.querySelector('.todo-count'); + const todoCount = new TodoCount({ + $targetCount: $todoCount, + $targetFilter: $todoFilter, + data: { + totalCount: this.data.length, + }, + }) + + const $todoInput = document.querySelector('.new-todo') + const todoInput = TodoInput($todoInput, + { + onAdd: (text) => { + const nextData = [...this.data] + nextData.push({ + text: text, + isCompleted: false, + isEditing: false + }) + this.setState(nextData) + } + } + ) +} \ No newline at end of file diff --git a/mission002/js/TodoCount.js b/mission002/js/TodoCount.js new file mode 100644 index 0000000..dd00a52 --- /dev/null +++ b/mission002/js/TodoCount.js @@ -0,0 +1,21 @@ +function TodoCount({$targetCount, $targetFilter, data, onFilterClick}) { + this.data = data; + this.$targetCount = $targetCount; + this.$targetFilter = $targetFilter; + + this.setState = function (nextData) { + this.data = nextData; + this.render(); + } + + if (this === window) { + throw new Error(error.NO_USED_NEW_KEYWORD) + } + + this.render = function () { + const { totalCount } = this.data + $targetCount.innerHTML = `총 ${totalCount}개` + } + this.render(); + +} \ No newline at end of file diff --git a/mission002/js/TodoInput.js b/mission002/js/TodoInput.js new file mode 100644 index 0000000..7cf19c6 --- /dev/null +++ b/mission002/js/TodoInput.js @@ -0,0 +1,9 @@ +function TodoInput($targetInput, {onAdd}) { + + $targetInput.addEventListener('keydown', (e) => { + if (e.key === "Enter") { + onAdd($targetInput.value) + $targetInput.value = ''; + } + }) +} \ No newline at end of file diff --git a/mission002/js/TodoList.js b/mission002/js/TodoList.js new file mode 100644 index 0000000..4d81606 --- /dev/null +++ b/mission002/js/TodoList.js @@ -0,0 +1,91 @@ +function TodoList({ $target, $targetFilter, data, onToggleClick, onTodoEdit, onRemoveClick, onTodoChange, onFilterClick }) { + this.$target = $target; + this.$targetFilter = $targetFilter + this.data = data; + + this.setState = function (nextData) { + this.data = nextData; + this.render() + } + + const filterTypes = document.querySelectorAll(".filters li a") + + if (this === window) { + throw new Error(error.NO_USED_NEW_KEYWORD) + } + else if (Array.isArray(this.data) === false) { + throw new Error(error.NOARRAY_DATA) + } + + this.$target.addEventListener('click', (e) => { + const { className } = e.target; + const { index } = e.target.parentNode.parentNode.dataset + if(!filterTypes[0].classList.contains("selected")) return + + if (className === 'toggle') { + onToggleClick(index) + } else if (className === 'destroy') { + onRemoveClick(index) + } + }) + + this.$target.addEventListener('dblclick', (e) => { + const { className } = e.target; + const { index } = e.target.closest('li').dataset + if (className === 'label') { + onTodoEdit(index) + } + }) + + this.$target.addEventListener('keydown', (e) => { + const { className } = e.target; + const { index } = e.target.parentNode.dataset; + if (className === 'edit') { + if (e.key === "Enter") { + onTodoChange(index, e.target.value) + } else if (e.key === "Escape") { + onTodoEdit(index) + } + } + }) + + this.$targetFilter.addEventListener('click', (e) => { + const { className } = e.target; + for (let val of filterTypes) { + if (val.classList.contains("selected")) { + val.classList.remove("selected") + } + } + e.target.classList.add("selected"); + + if (className.includes('all')) { + onFilterClick() + } else if (className.includes('active')) { + onFilterClick(true) + } else if (className.includes('completed')) { + onFilterClick(false) + } + }) + + this.render = function () { + const renderedHTMLText = this.data.map((val, idx) => { + if (!val.text) { + throw new Error(error.NOT_DATA) + } + else if (typeof (val.text) !== "string") { + throw new Error(error.INVALID_DATA) + } + return ` +
  • +
    + + + +
    + +
  • ` + }).join(''); + this.$target.innerHTML = renderedHTMLText + } + this.render() +} \ No newline at end of file diff --git a/mission002/js/constant.js b/mission002/js/constant.js new file mode 100644 index 0000000..a515344 --- /dev/null +++ b/mission002/js/constant.js @@ -0,0 +1,19 @@ +const error = { + NO_USED_NEW_KEYWORD: "함수 선언시 new를 사용해주세요.", + NOARRAY_DATA: "data타입이 Array가 아닙니다.", + NOT_DATA: "data가 null 또는 undefined 입니다.", + INVALID_DATA: "data타입이 문자열이 아닙니다.", +}; + +const data = [ + { + text: 'JS 공부하기', + isCompleted : false, + isEditing : false, + }, + { + text: 'JS 복습하기', + isCompleted: true, + isEditing : false, + }, +] diff --git a/mission002/js/index.js b/mission002/js/index.js new file mode 100644 index 0000000..05f4a06 --- /dev/null +++ b/mission002/js/index.js @@ -0,0 +1 @@ +new App(data); \ No newline at end of file From b5194aa363aad7daa322183c6b72c826f324b3c0 Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Fri, 3 Jan 2020 22:41:04 +0900 Subject: [PATCH 02/20] =?UTF-8?q?M2=20edit=EA=B8=B0=EB=8A=A5=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 113 ++------------------------------------ mission002/js/App.js | 19 +------ mission002/js/TodoList.js | 34 +++--------- mission002/js/constant.js | 13 ++--- 4 files changed, 19 insertions(+), 160 deletions(-) diff --git a/.gitignore b/.gitignore index bdda98f..afba0a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,107 +1,6 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache - -# Next.js build output -.next - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and *not* Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# idea -.idea/** +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace diff --git a/mission002/js/App.js b/mission002/js/App.js index cf78cf6..94c5d43 100644 --- a/mission002/js/App.js +++ b/mission002/js/App.js @@ -26,27 +26,11 @@ function App(data) { nextData[index].isCompleted = !nextData[index].isCompleted this.setState(nextData) }, - onTodoEdit: (index) => { - const nextData = [...this.data] - if (!nextData[index].isCompleted) { - nextData[index].isEditing = !nextData[index].isEditing - } - this.setState(nextData) - }, onRemoveClick: (index) => { const nextData = [...this.data] nextData.splice(index, 1) this.setState(nextData) }, - onTodoChange: (index, value) => { - const nextData = [...this.data] - nextData[index] = { - text: value, - isCompleted: false, - isEditing: false - }; - this.setState(nextData) - }, onFilterClick: (filterBoolean) => { let filteredData = [...this.data] filteredData = this.data.filter(todo => todo.isCompleted !== filterBoolean) @@ -69,9 +53,8 @@ function App(data) { onAdd: (text) => { const nextData = [...this.data] nextData.push({ - text: text, + content: text, isCompleted: false, - isEditing: false }) this.setState(nextData) } diff --git a/mission002/js/TodoList.js b/mission002/js/TodoList.js index 4d81606..a9cbb79 100644 --- a/mission002/js/TodoList.js +++ b/mission002/js/TodoList.js @@ -1,4 +1,4 @@ -function TodoList({ $target, $targetFilter, data, onToggleClick, onTodoEdit, onRemoveClick, onTodoChange, onFilterClick }) { +function TodoList({ $target, $targetFilter, data, onToggleClick, onRemoveClick, onFilterClick }) { this.$target = $target; this.$targetFilter = $targetFilter this.data = data; @@ -29,26 +29,6 @@ function TodoList({ $target, $targetFilter, data, onToggleClick, onTodoEdit, onR } }) - this.$target.addEventListener('dblclick', (e) => { - const { className } = e.target; - const { index } = e.target.closest('li').dataset - if (className === 'label') { - onTodoEdit(index) - } - }) - - this.$target.addEventListener('keydown', (e) => { - const { className } = e.target; - const { index } = e.target.parentNode.dataset; - if (className === 'edit') { - if (e.key === "Enter") { - onTodoChange(index, e.target.value) - } else if (e.key === "Escape") { - onTodoEdit(index) - } - } - }) - this.$targetFilter.addEventListener('click', (e) => { const { className } = e.target; for (let val of filterTypes) { @@ -69,22 +49,24 @@ function TodoList({ $target, $targetFilter, data, onToggleClick, onTodoEdit, onR this.render = function () { const renderedHTMLText = this.data.map((val, idx) => { - if (!val.text) { + if (!val.content) { throw new Error(error.NOT_DATA) } - else if (typeof (val.text) !== "string") { + else if (typeof (val.content) !== "string") { throw new Error(error.INVALID_DATA) } + //
  • return ` -
  • +
  • - +
    - +
  • ` }).join(''); + this.$target.innerHTML = renderedHTMLText } this.render() diff --git a/mission002/js/constant.js b/mission002/js/constant.js index a515344..f752da8 100644 --- a/mission002/js/constant.js +++ b/mission002/js/constant.js @@ -7,13 +7,8 @@ const error = { const data = [ { - text: 'JS 공부하기', - isCompleted : false, - isEditing : false, - }, - { - text: 'JS 복습하기', - isCompleted: true, - isEditing : false, - }, + "_id": 'TODO01', + "content": 'Fetch 공부', + "isCompleted": false, + } ] From d67b1037255d8aa25186f610554a335ac0f6d42a Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Sat, 4 Jan 2020 18:37:11 +0900 Subject: [PATCH 03/20] =?UTF-8?q?M2-1=20=ED=95=A0=EC=9D=BC=20=EB=B6=88?= =?UTF-8?q?=EB=9F=AC=EC=98=A4=EA=B8=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission002/index.html | 5 +-- mission002/js/TodoList.js | 1 - mission002/js/constant.js | 17 +++++---- mission002/js/index.js | 72 ++++++++++++++++++++++++++++++++++++++- mission002/js/main.js | 56 ++++++++++++++++++++++++++++++ 5 files changed, 140 insertions(+), 11 deletions(-) create mode 100644 mission002/js/main.js diff --git a/mission002/index.html b/mission002/index.html index 6d17d43..0c971e4 100644 --- a/mission002/index.html +++ b/mission002/index.html @@ -3,7 +3,7 @@ - 이벤트 - TODOS + Fetch - TODOS @@ -56,7 +56,8 @@

    TODOS

    - + + diff --git a/mission002/js/TodoList.js b/mission002/js/TodoList.js index a9cbb79..c876374 100644 --- a/mission002/js/TodoList.js +++ b/mission002/js/TodoList.js @@ -7,7 +7,6 @@ function TodoList({ $target, $targetFilter, data, onToggleClick, onRemoveClick, this.data = nextData; this.render() } - const filterTypes = document.querySelectorAll(".filters li a") if (this === window) { diff --git a/mission002/js/constant.js b/mission002/js/constant.js index f752da8..c89f752 100644 --- a/mission002/js/constant.js +++ b/mission002/js/constant.js @@ -5,10 +5,13 @@ const error = { INVALID_DATA: "data타입이 문자열이 아닙니다.", }; -const data = [ - { - "_id": 'TODO01', - "content": 'Fetch 공부', - "isCompleted": false, - } -] +const USERNAME = 'ganeodolu'; + +const APIURL = `http://todo-api.roto.codes/${USERNAME}/`; +// const data = [ +// { +// "_id": 'TODO01', +// "content": 'Fetch 공부', +// "isCompleted": false, +// } +// ] diff --git a/mission002/js/index.js b/mission002/js/index.js index 05f4a06..7571d1a 100644 --- a/mission002/js/index.js +++ b/mission002/js/index.js @@ -1 +1,71 @@ -new App(data); \ No newline at end of file +;(async function(){ + async function fetchData(){ + const res = await fetch(APIURL) + return await res.json() + } + const data = await fetchData() + + this.data = data; + this.render = function (filteredData) { + todoList.setState(filteredData) + todoCount.render(filteredData) + todoCount.setState({ + totalCount: filteredData.length, + }) + } + this.setState = function (nextData) { + this.data = nextData; + todoList.setState(this.data) + todoCount.setState({ + totalCount: this.data.length, + }) + } + + + const $todoList = document.querySelector('.todo-list') + const $todoFilter = document.querySelector('.filters'); + const todoList = new TodoList({ + $target: $todoList, + $targetFilter: $todoFilter, + data: this.data, + onToggleClick: (index) => { + const nextData = [...this.data] + nextData[index].isCompleted = !nextData[index].isCompleted + this.setState(nextData) + }, + onRemoveClick: (index) => { + const nextData = [...this.data] + nextData.splice(index, 1) + this.setState(nextData) + }, + onFilterClick: (filterBoolean) => { + let filteredData = [...this.data] + filteredData = this.data.filter(todo => todo.isCompleted !== filterBoolean) + this.render(filteredData) + } + }); + + const $todoCount = document.querySelector('.todo-count'); + const todoCount = new TodoCount({ + $targetCount: $todoCount, + $targetFilter: $todoFilter, + data: { + totalCount: this.data.length, + }, + }) + + const $todoInput = document.querySelector('.new-todo') + const todoInput = TodoInput($todoInput, + { + onAdd: (text) => { + const nextData = [...this.data] + nextData.push({ + content: text, + isCompleted: false, + }) + this.setState(nextData) + } + } + ) +})() + diff --git a/mission002/js/main.js b/mission002/js/main.js new file mode 100644 index 0000000..7c896a2 --- /dev/null +++ b/mission002/js/main.js @@ -0,0 +1,56 @@ +; (async function () { + const username = 'ganeodolu' + + async function fetchData() { + const res = await fetch(`http://todo-api.roto.codes/${username}`) + return await res.json() + } + + const data = await fetchData() + + const todoList = new TodoList({ + $target: document.querySelector('#todo-list'), + data: data, + onClick: async function (id) { + await fetch(`http://todo-api.roto.codes/${username}/${id}/toggle`, { + method: 'PUT', + }) + + // 데이터 추가 후 서버에서 목록 다시 불러서 다시 그리기 + const updatedData = await fetchData() + todoList.setState(updatedData) + }, + onRemove: async function (id) { + await fetch(`http://todo-api.roto.codes/${username}/${id}`, { + method: 'DELETE', + }) + + // 데이터 추가 후 서버에서 목록 다시 불러서 다시 그리기 + const updatedData = await fetchData() + todoList.setState(updatedData) + }, + }) + + document + .querySelector('#add-todo-button') + .addEventListener('click', async function () { + const todoText = document.querySelector('#todo-input').value + + if (todoText.length > 0) { + // 데이터 추가하기 + await fetch(`http://todo-api.roto.codes/${username}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + content: todoText, + }), + }) + + // 데이터 추가 후 서버에서 목록 다시 불러서 다시 그리기 + const updatedData = await fetchData() + todoList.setState(updatedData) + } + }) +})() \ No newline at end of file From 5f81777679e137da3f18df6f95e197610ce92711 Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Sat, 4 Jan 2020 18:55:47 +0900 Subject: [PATCH 04/20] =?UTF-8?q?M2-2=20=ED=95=A0=EC=9D=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=ED=95=98=EA=B8=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 8 ++++++++ mission002/js/TodoInput.js | 4 ++-- mission002/js/index.js | 32 +++++++++++++++++++++++++------- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index afba0a7..7a49211 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,11 @@ !.vscode/launch.json !.vscode/extensions.json *.code-workspace + +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace +.vscode/settings.json diff --git a/mission002/js/TodoInput.js b/mission002/js/TodoInput.js index 7cf19c6..945370e 100644 --- a/mission002/js/TodoInput.js +++ b/mission002/js/TodoInput.js @@ -1,8 +1,8 @@ function TodoInput($targetInput, {onAdd}) { - $targetInput.addEventListener('keydown', (e) => { + $targetInput.addEventListener('keydown', async (e) => { if (e.key === "Enter") { - onAdd($targetInput.value) + await onAdd($targetInput.value) $targetInput.value = ''; } }) diff --git a/mission002/js/index.js b/mission002/js/index.js index 7571d1a..8fa12b1 100644 --- a/mission002/js/index.js +++ b/mission002/js/index.js @@ -57,14 +57,32 @@ const $todoInput = document.querySelector('.new-todo') const todoInput = TodoInput($todoInput, { - onAdd: (text) => { - const nextData = [...this.data] - nextData.push({ - content: text, - isCompleted: false, - }) - this.setState(nextData) + onAdd: async (todoText) => { + if(todoText.length > 0){ + await fetch(APIURL,{ + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + content: todoText, + }), + }) + const updatedData = await fetchData(); + todoList.setState(updatedData) + + } + } + + // onAdd: (text) => { + // const nextData = [...this.data] + // nextData.push({ + // content: text, + // isCompleted: false, + // }) + // this.setState(nextData) + // } } ) })() From 757f6310d7901e6e9f0b2339de2a47410645dfae Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Sun, 5 Jan 2020 18:13:43 +0900 Subject: [PATCH 05/20] =?UTF-8?q?M2-3,4=20=ED=95=A0=EC=9D=BC=EC=82=AD?= =?UTF-8?q?=EC=A0=9C,=20=ED=86=A0=EA=B8=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission002/index.html | 8 ++--- mission002/js/TodoInput.js | 4 +-- mission002/js/TodoList.js | 7 +++-- mission002/js/constant.js | 2 +- mission002/js/index.js | 60 ++++++++++++++++++-------------------- 5 files changed, 41 insertions(+), 40 deletions(-) diff --git a/mission002/index.html b/mission002/index.html index 0c971e4..6938d0b 100644 --- a/mission002/index.html +++ b/mission002/index.html @@ -15,11 +15,11 @@

    TODOS

      -
    • + +
    @@ -38,7 +38,7 @@

    TODOS

    - + -->
    diff --git a/mission002/js/TodoInput.js b/mission002/js/TodoInput.js index 945370e..7cf19c6 100644 --- a/mission002/js/TodoInput.js +++ b/mission002/js/TodoInput.js @@ -1,8 +1,8 @@ function TodoInput($targetInput, {onAdd}) { - $targetInput.addEventListener('keydown', async (e) => { + $targetInput.addEventListener('keydown', (e) => { if (e.key === "Enter") { - await onAdd($targetInput.value) + onAdd($targetInput.value) $targetInput.value = ''; } }) diff --git a/mission002/js/TodoList.js b/mission002/js/TodoList.js index c876374..03a61f1 100644 --- a/mission002/js/TodoList.js +++ b/mission002/js/TodoList.js @@ -19,12 +19,15 @@ function TodoList({ $target, $targetFilter, data, onToggleClick, onRemoveClick, this.$target.addEventListener('click', (e) => { const { className } = e.target; const { index } = e.target.parentNode.parentNode.dataset + console.log(index) + const id = data[index]._id if(!filterTypes[0].classList.contains("selected")) return if (className === 'toggle') { - onToggleClick(index) + console.log(data[index]) + onToggleClick(id) } else if (className === 'destroy') { - onRemoveClick(index) + onRemoveClick(id) } }) diff --git a/mission002/js/constant.js b/mission002/js/constant.js index c89f752..5e08d8c 100644 --- a/mission002/js/constant.js +++ b/mission002/js/constant.js @@ -7,7 +7,7 @@ const error = { const USERNAME = 'ganeodolu'; -const APIURL = `http://todo-api.roto.codes/${USERNAME}/`; +const APIURL = `http://todo-api.roto.codes/${USERNAME}`; // const data = [ // { // "_id": 'TODO01', diff --git a/mission002/js/index.js b/mission002/js/index.js index 8fa12b1..484fd4c 100644 --- a/mission002/js/index.js +++ b/mission002/js/index.js @@ -6,20 +6,20 @@ const data = await fetchData() this.data = data; - this.render = function (filteredData) { - todoList.setState(filteredData) - todoCount.render(filteredData) - todoCount.setState({ - totalCount: filteredData.length, - }) - } - this.setState = function (nextData) { - this.data = nextData; - todoList.setState(this.data) - todoCount.setState({ - totalCount: this.data.length, - }) - } + // this.render = function (filteredData) { + // todoList.setState(filteredData) + // todoCount.render(filteredData) + // todoCount.setState({ + // totalCount: filteredData.length, + // }) + // } + // this.setState = function (nextData) { + // this.data = nextData; + // todoList.setState(this.data) + // todoCount.setState({ + // totalCount: this.data.length, + // }) + // } const $todoList = document.querySelector('.todo-list') @@ -28,15 +28,22 @@ $target: $todoList, $targetFilter: $todoFilter, data: this.data, - onToggleClick: (index) => { - const nextData = [...this.data] - nextData[index].isCompleted = !nextData[index].isCompleted - this.setState(nextData) + onToggleClick: async (id) => { + console.log(id) + await fetch(`${APIURL}/${id}/toggle`, { + method: "PUT", + }) + const updatedData = await fetchData() + todoList.setState(updatedData) }, - onRemoveClick: (index) => { - const nextData = [...this.data] - nextData.splice(index, 1) - this.setState(nextData) + onRemoveClick: async (id) => { + console.log(id) + await fetch(`${APIURL}/${id}`, { + method: 'DELETE' + }) + + const updatedData = await fetchData() + todoList.setState(updatedData) }, onFilterClick: (filterBoolean) => { let filteredData = [...this.data] @@ -74,15 +81,6 @@ } } - - // onAdd: (text) => { - // const nextData = [...this.data] - // nextData.push({ - // content: text, - // isCompleted: false, - // }) - // this.setState(nextData) - // } } ) })() From f012f6e5b358688a5c136a74f4e32d531c5b191e Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Sun, 5 Jan 2020 20:02:23 +0900 Subject: [PATCH 06/20] =?UTF-8?q?M2=20import=EB=A5=BC=20=EC=B7=A8=ED=95=98?= =?UTF-8?q?=EA=B3=A0=20=EC=83=9D=EC=84=B1=EC=9E=90=EB=A5=BC=20=EB=82=B4?= =?UTF-8?q?=EC=A4=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit export default async function App(){} 이렇게 하니 App이 생성자가 아니라고 하옴 --- mission002/index.html | 11 ++--- mission002/js/App.js | 95 +++++++++++++++++++++++--------------- mission002/js/TodoCount.js | 2 +- mission002/js/TodoInput.js | 2 +- mission002/js/TodoList.js | 4 +- mission002/js/api.js | 6 +++ mission002/js/constant.js | 4 +- mission002/js/index.js | 88 +---------------------------------- mission002/js/main.js | 56 ---------------------- 9 files changed, 78 insertions(+), 190 deletions(-) create mode 100644 mission002/js/api.js delete mode 100644 mission002/js/main.js diff --git a/mission002/index.html b/mission002/index.html index 6938d0b..8265d86 100644 --- a/mission002/index.html +++ b/mission002/index.html @@ -57,11 +57,10 @@

    TODOS

    - - - - - - + + + + + diff --git a/mission002/js/App.js b/mission002/js/App.js index 94c5d43..76d363b 100644 --- a/mission002/js/App.js +++ b/mission002/js/App.js @@ -1,40 +1,49 @@ -function App(data) { - this.data = data; - this.render = function (filteredData) { - todoList.setState(filteredData) - todoCount.render(filteredData) - todoCount.setState({ - totalCount: filteredData.length, - }) - } - this.setState = function (nextData) { - this.data = nextData; - todoList.setState(this.data) - todoCount.setState({ - totalCount: this.data.length, - }) - } +import TodoList from './TodoList.js' +import TodoInput from './TodoInput.js' +import TodoCount from './TodoCount.js' +import { APIURL } from './constant.js' +import { fetchData } from './api.js'; + +export default async function app(){ + + const data = await fetchData() const $todoList = document.querySelector('.todo-list') const $todoFilter = document.querySelector('.filters'); const todoList = new TodoList({ $target: $todoList, $targetFilter: $todoFilter, - data: this.data, - onToggleClick: (index) => { - const nextData = [...this.data] - nextData[index].isCompleted = !nextData[index].isCompleted - this.setState(nextData) + data: data, + onToggleClick: async (id) => { + console.log(id) + await fetch(`${APIURL}/${id}/toggle`, { + method: "PUT", + }) + const updatedData = await fetchData() + todoList.setState(updatedData) + todoCount.setState({ + totalCount: updatedData.length + }) }, - onRemoveClick: (index) => { - const nextData = [...this.data] - nextData.splice(index, 1) - this.setState(nextData) + onRemoveClick: async (id) => { + console.log(id) + await fetch(`${APIURL}/${id}`, { + method: 'DELETE' + }) + + const updatedData = await fetchData() + todoList.setState(updatedData) + todoCount.setState({ + totalCount: filteredData.length + }) }, onFilterClick: (filterBoolean) => { - let filteredData = [...this.data] - filteredData = this.data.filter(todo => todo.isCompleted !== filterBoolean) - this.render(filteredData) + let filteredData = [...data] + filteredData = data.filter(todo => todo.isCompleted !== filterBoolean) + todoList.setState(filteredData) + todoCount.setState({ + totalCount: filteredData.length + }) } }); @@ -43,21 +52,33 @@ function App(data) { $targetCount: $todoCount, $targetFilter: $todoFilter, data: { - totalCount: this.data.length, + totalCount: data.length, }, }) const $todoInput = document.querySelector('.new-todo') const todoInput = TodoInput($todoInput, { - onAdd: (text) => { - const nextData = [...this.data] - nextData.push({ - content: text, - isCompleted: false, - }) - this.setState(nextData) + onAdd: async (todoText) => { + if (todoText.length > 0) { + await fetch(APIURL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + content: todoText, + }), + }) + const updatedData = await fetchData(); + todoList.setState(updatedData) + todoCount.setState({ + totalCount: updatedData.length + }) + } + } } ) -} \ No newline at end of file +} + diff --git a/mission002/js/TodoCount.js b/mission002/js/TodoCount.js index dd00a52..7b8635f 100644 --- a/mission002/js/TodoCount.js +++ b/mission002/js/TodoCount.js @@ -1,4 +1,4 @@ -function TodoCount({$targetCount, $targetFilter, data, onFilterClick}) { +export default function TodoCount({$targetCount, $targetFilter, data, onFilterClick}) { this.data = data; this.$targetCount = $targetCount; this.$targetFilter = $targetFilter; diff --git a/mission002/js/TodoInput.js b/mission002/js/TodoInput.js index 7cf19c6..9b66b0b 100644 --- a/mission002/js/TodoInput.js +++ b/mission002/js/TodoInput.js @@ -1,4 +1,4 @@ -function TodoInput($targetInput, {onAdd}) { +export default function TodoInput($targetInput, {onAdd}) { $targetInput.addEventListener('keydown', (e) => { if (e.key === "Enter") { diff --git a/mission002/js/TodoList.js b/mission002/js/TodoList.js index 03a61f1..7306bdd 100644 --- a/mission002/js/TodoList.js +++ b/mission002/js/TodoList.js @@ -1,4 +1,6 @@ -function TodoList({ $target, $targetFilter, data, onToggleClick, onRemoveClick, onFilterClick }) { +import { error } from './constant.js' + +export default function TodoList({ $target, $targetFilter, data, onToggleClick, onRemoveClick, onFilterClick }) { this.$target = $target; this.$targetFilter = $targetFilter this.data = data; diff --git a/mission002/js/api.js b/mission002/js/api.js new file mode 100644 index 0000000..ec6e4b3 --- /dev/null +++ b/mission002/js/api.js @@ -0,0 +1,6 @@ +import { APIURL } from './constant.js' + +export async function fetchData() { + const res = await fetch(APIURL) + return await res.json() +} \ No newline at end of file diff --git a/mission002/js/constant.js b/mission002/js/constant.js index 5e08d8c..09c4546 100644 --- a/mission002/js/constant.js +++ b/mission002/js/constant.js @@ -1,4 +1,4 @@ -const error = { +export const error = { NO_USED_NEW_KEYWORD: "함수 선언시 new를 사용해주세요.", NOARRAY_DATA: "data타입이 Array가 아닙니다.", NOT_DATA: "data가 null 또는 undefined 입니다.", @@ -7,7 +7,7 @@ const error = { const USERNAME = 'ganeodolu'; -const APIURL = `http://todo-api.roto.codes/${USERNAME}`; +export const APIURL = `http://todo-api.roto.codes/${USERNAME}`; // const data = [ // { // "_id": 'TODO01', diff --git a/mission002/js/index.js b/mission002/js/index.js index 484fd4c..0060c17 100644 --- a/mission002/js/index.js +++ b/mission002/js/index.js @@ -1,87 +1,3 @@ -;(async function(){ - async function fetchData(){ - const res = await fetch(APIURL) - return await res.json() - } - const data = await fetchData() - - this.data = data; - // this.render = function (filteredData) { - // todoList.setState(filteredData) - // todoCount.render(filteredData) - // todoCount.setState({ - // totalCount: filteredData.length, - // }) - // } - // this.setState = function (nextData) { - // this.data = nextData; - // todoList.setState(this.data) - // todoCount.setState({ - // totalCount: this.data.length, - // }) - // } - - - const $todoList = document.querySelector('.todo-list') - const $todoFilter = document.querySelector('.filters'); - const todoList = new TodoList({ - $target: $todoList, - $targetFilter: $todoFilter, - data: this.data, - onToggleClick: async (id) => { - console.log(id) - await fetch(`${APIURL}/${id}/toggle`, { - method: "PUT", - }) - const updatedData = await fetchData() - todoList.setState(updatedData) - }, - onRemoveClick: async (id) => { - console.log(id) - await fetch(`${APIURL}/${id}`, { - method: 'DELETE' - }) - - const updatedData = await fetchData() - todoList.setState(updatedData) - }, - onFilterClick: (filterBoolean) => { - let filteredData = [...this.data] - filteredData = this.data.filter(todo => todo.isCompleted !== filterBoolean) - this.render(filteredData) - } - }); - - const $todoCount = document.querySelector('.todo-count'); - const todoCount = new TodoCount({ - $targetCount: $todoCount, - $targetFilter: $todoFilter, - data: { - totalCount: this.data.length, - }, - }) - - const $todoInput = document.querySelector('.new-todo') - const todoInput = TodoInput($todoInput, - { - onAdd: async (todoText) => { - if(todoText.length > 0){ - await fetch(APIURL,{ - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - content: todoText, - }), - }) - const updatedData = await fetchData(); - todoList.setState(updatedData) - - } - - } - } - ) -})() +import app from './App.js' +app() \ No newline at end of file diff --git a/mission002/js/main.js b/mission002/js/main.js deleted file mode 100644 index 7c896a2..0000000 --- a/mission002/js/main.js +++ /dev/null @@ -1,56 +0,0 @@ -; (async function () { - const username = 'ganeodolu' - - async function fetchData() { - const res = await fetch(`http://todo-api.roto.codes/${username}`) - return await res.json() - } - - const data = await fetchData() - - const todoList = new TodoList({ - $target: document.querySelector('#todo-list'), - data: data, - onClick: async function (id) { - await fetch(`http://todo-api.roto.codes/${username}/${id}/toggle`, { - method: 'PUT', - }) - - // 데이터 추가 후 서버에서 목록 다시 불러서 다시 그리기 - const updatedData = await fetchData() - todoList.setState(updatedData) - }, - onRemove: async function (id) { - await fetch(`http://todo-api.roto.codes/${username}/${id}`, { - method: 'DELETE', - }) - - // 데이터 추가 후 서버에서 목록 다시 불러서 다시 그리기 - const updatedData = await fetchData() - todoList.setState(updatedData) - }, - }) - - document - .querySelector('#add-todo-button') - .addEventListener('click', async function () { - const todoText = document.querySelector('#todo-input').value - - if (todoText.length > 0) { - // 데이터 추가하기 - await fetch(`http://todo-api.roto.codes/${username}`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - content: todoText, - }), - }) - - // 데이터 추가 후 서버에서 목록 다시 불러서 다시 그리기 - const updatedData = await fetchData() - todoList.setState(updatedData) - } - }) -})() \ No newline at end of file From 11bee1fade3d4149dbe884a46e7dda8c076bdc53 Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Sun, 5 Jan 2020 21:03:54 +0900 Subject: [PATCH 07/20] =?UTF-8?q?M2=20=ED=95=A0=EC=9D=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=ED=9B=84=20=ED=86=A0=EA=B8=80=20=EB=B0=8F=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EC=98=A4=EB=A5=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 제대로 된 id를 못찾음 --- mission002/index.html | 5 -- mission002/js/App.js | 141 +++++++++++++++++++------------------- mission002/js/TodoList.js | 10 ++- mission002/js/constant.js | 8 +-- mission002/js/index.js | 3 +- 5 files changed, 75 insertions(+), 92 deletions(-) diff --git a/mission002/index.html b/mission002/index.html index 8265d86..4305188 100644 --- a/mission002/index.html +++ b/mission002/index.html @@ -56,11 +56,6 @@

    TODOS

    - - - - - diff --git a/mission002/js/App.js b/mission002/js/App.js index 76d363b..9482857 100644 --- a/mission002/js/App.js +++ b/mission002/js/App.js @@ -5,80 +5,77 @@ import { APIURL } from './constant.js' import { fetchData } from './api.js'; export default async function app(){ + // ;(async function(){ + const data = await fetchData() - const data = await fetchData() - - const $todoList = document.querySelector('.todo-list') - const $todoFilter = document.querySelector('.filters'); - const todoList = new TodoList({ - $target: $todoList, - $targetFilter: $todoFilter, - data: data, - onToggleClick: async (id) => { - console.log(id) - await fetch(`${APIURL}/${id}/toggle`, { - method: "PUT", - }) - const updatedData = await fetchData() - todoList.setState(updatedData) - todoCount.setState({ - totalCount: updatedData.length - }) - }, - onRemoveClick: async (id) => { - console.log(id) - await fetch(`${APIURL}/${id}`, { - method: 'DELETE' - }) - - const updatedData = await fetchData() - todoList.setState(updatedData) - todoCount.setState({ - totalCount: filteredData.length - }) - }, - onFilterClick: (filterBoolean) => { - let filteredData = [...data] - filteredData = data.filter(todo => todo.isCompleted !== filterBoolean) - todoList.setState(filteredData) - todoCount.setState({ - totalCount: filteredData.length - }) - } - }); - - const $todoCount = document.querySelector('.todo-count'); - const todoCount = new TodoCount({ - $targetCount: $todoCount, - $targetFilter: $todoFilter, - data: { - totalCount: data.length, - }, - }) - - const $todoInput = document.querySelector('.new-todo') - const todoInput = TodoInput($todoInput, - { - onAdd: async (todoText) => { - if (todoText.length > 0) { - await fetch(APIURL, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - content: todoText, - }), - }) - const updatedData = await fetchData(); - todoList.setState(updatedData) - todoCount.setState({ - totalCount: updatedData.length - }) + const $todoList = document.querySelector('.todo-list') + const $todoFilter = document.querySelector('.filters'); + const todoList = new TodoList({ + $target: $todoList, + $targetFilter: $todoFilter, + data: data, + onToggleClick: async (id) => { + await fetch(`${APIURL}/${id}/toggle`, { + method: "PUT", + }) + const updatedData = await fetchData() + todoList.setState(updatedData) + todoCount.setState({ + totalCount: updatedData.length + }) + }, + onRemoveClick: async (id) => { + await fetch(`${APIURL}/${id}`, { + method: 'DELETE' + }) + const updatedData = await fetchData() + todoList.setState(updatedData) + todoCount.setState({ + totalCount: updatedData.length + }) + }, + onFilterClick: (filterBoolean) => { + let filteredData = [...data] + filteredData = data.filter(todo => todo.isCompleted !== filterBoolean) + todoList.setState(filteredData) + todoCount.setState({ + totalCount: filteredData.length + }) + } + }); + + const $todoCount = document.querySelector('.todo-count'); + const todoCount = new TodoCount({ + $targetCount: $todoCount, + $targetFilter: $todoFilter, + data: { + totalCount: data.length, + }, + }) + + const $todoInput = document.querySelector('.new-todo') + const todoInput = TodoInput($todoInput, + { + onAdd: async (todoText) => { + if (todoText.length > 0) { + await fetch(APIURL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + content: todoText, + }), + }) + const updatedData = await fetchData(); + todoList.setState(updatedData) + todoCount.setState({ + totalCount: updatedData.length + }) + } } - } - } - ) + ) + // }) } diff --git a/mission002/js/TodoList.js b/mission002/js/TodoList.js index 7306bdd..f99d44f 100644 --- a/mission002/js/TodoList.js +++ b/mission002/js/TodoList.js @@ -18,15 +18,13 @@ export default function TodoList({ $target, $targetFilter, data, onToggleClick, throw new Error(error.NOARRAY_DATA) } - this.$target.addEventListener('click', (e) => { + this.$target.addEventListener('click', async (e) => { const { className } = e.target; const { index } = e.target.parentNode.parentNode.dataset - console.log(index) - const id = data[index]._id - if(!filterTypes[0].classList.contains("selected")) return - + + const id = await data[index]._id + if (!filterTypes[0].classList.contains("selected")) return if (className === 'toggle') { - console.log(data[index]) onToggleClick(id) } else if (className === 'destroy') { onRemoveClick(id) diff --git a/mission002/js/constant.js b/mission002/js/constant.js index 09c4546..9373f2c 100644 --- a/mission002/js/constant.js +++ b/mission002/js/constant.js @@ -8,10 +8,4 @@ export const error = { const USERNAME = 'ganeodolu'; export const APIURL = `http://todo-api.roto.codes/${USERNAME}`; -// const data = [ -// { -// "_id": 'TODO01', -// "content": 'Fetch 공부', -// "isCompleted": false, -// } -// ] + diff --git a/mission002/js/index.js b/mission002/js/index.js index 0060c17..ea49186 100644 --- a/mission002/js/index.js +++ b/mission002/js/index.js @@ -1,3 +1,2 @@ import app from './App.js' - -app() \ No newline at end of file +app() From f3b397e133859dc6c3fbb575f67a218ea2c21565 Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Mon, 6 Jan 2020 19:16:21 +0900 Subject: [PATCH 08/20] =?UTF-8?q?M2=20=EA=B8=B0=EC=A1=B4=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=20ganeodolu=ED=8F=B4=EB=8D=94=EC=95=88=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission002/{ => ganeodolu}/css/style.css | 0 mission002/{ => ganeodolu}/index.html | 0 mission002/{ => ganeodolu}/js/App.js | 0 mission002/{ => ganeodolu}/js/TodoCount.js | 0 mission002/{ => ganeodolu}/js/TodoInput.js | 0 mission002/{ => ganeodolu}/js/TodoList.js | 0 mission002/{ => ganeodolu}/js/api.js | 0 mission002/{ => ganeodolu}/js/constant.js | 0 mission002/{ => ganeodolu}/js/index.js | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename mission002/{ => ganeodolu}/css/style.css (100%) rename mission002/{ => ganeodolu}/index.html (100%) rename mission002/{ => ganeodolu}/js/App.js (100%) rename mission002/{ => ganeodolu}/js/TodoCount.js (100%) rename mission002/{ => ganeodolu}/js/TodoInput.js (100%) rename mission002/{ => ganeodolu}/js/TodoList.js (100%) rename mission002/{ => ganeodolu}/js/api.js (100%) rename mission002/{ => ganeodolu}/js/constant.js (100%) rename mission002/{ => ganeodolu}/js/index.js (100%) diff --git a/mission002/css/style.css b/mission002/ganeodolu/css/style.css similarity index 100% rename from mission002/css/style.css rename to mission002/ganeodolu/css/style.css diff --git a/mission002/index.html b/mission002/ganeodolu/index.html similarity index 100% rename from mission002/index.html rename to mission002/ganeodolu/index.html diff --git a/mission002/js/App.js b/mission002/ganeodolu/js/App.js similarity index 100% rename from mission002/js/App.js rename to mission002/ganeodolu/js/App.js diff --git a/mission002/js/TodoCount.js b/mission002/ganeodolu/js/TodoCount.js similarity index 100% rename from mission002/js/TodoCount.js rename to mission002/ganeodolu/js/TodoCount.js diff --git a/mission002/js/TodoInput.js b/mission002/ganeodolu/js/TodoInput.js similarity index 100% rename from mission002/js/TodoInput.js rename to mission002/ganeodolu/js/TodoInput.js diff --git a/mission002/js/TodoList.js b/mission002/ganeodolu/js/TodoList.js similarity index 100% rename from mission002/js/TodoList.js rename to mission002/ganeodolu/js/TodoList.js diff --git a/mission002/js/api.js b/mission002/ganeodolu/js/api.js similarity index 100% rename from mission002/js/api.js rename to mission002/ganeodolu/js/api.js diff --git a/mission002/js/constant.js b/mission002/ganeodolu/js/constant.js similarity index 100% rename from mission002/js/constant.js rename to mission002/ganeodolu/js/constant.js diff --git a/mission002/js/index.js b/mission002/ganeodolu/js/index.js similarity index 100% rename from mission002/js/index.js rename to mission002/ganeodolu/js/index.js From dafe39ea7443184e33ec9081d2b9c23352b7de1d Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Mon, 6 Jan 2020 21:00:00 +0900 Subject: [PATCH 09/20] =?UTF-8?q?M3=20=EC=BB=A4=EB=B0=8B=20revert=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EB=90=98=EB=8F=8C=EB=A6=AC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission002/ganeodolu/index.html | 8 +-- mission002/ganeodolu/js/TodoInput.js | 4 +- mission002/js/index.js | 78 ++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 mission002/js/index.js diff --git a/mission002/ganeodolu/index.html b/mission002/ganeodolu/index.html index 4305188..d689139 100644 --- a/mission002/ganeodolu/index.html +++ b/mission002/ganeodolu/index.html @@ -15,11 +15,11 @@

    TODOS

      -
    @@ -38,7 +38,7 @@

    TODOS

    - --> +
    diff --git a/mission002/ganeodolu/js/TodoInput.js b/mission002/ganeodolu/js/TodoInput.js index 9b66b0b..d23664c 100644 --- a/mission002/ganeodolu/js/TodoInput.js +++ b/mission002/ganeodolu/js/TodoInput.js @@ -1,8 +1,8 @@ export default function TodoInput($targetInput, {onAdd}) { - $targetInput.addEventListener('keydown', (e) => { + $targetInput.addEventListener('keydown', async (e) => { if (e.key === "Enter") { - onAdd($targetInput.value) + await onAdd($targetInput.value) $targetInput.value = ''; } }) diff --git a/mission002/js/index.js b/mission002/js/index.js new file mode 100644 index 0000000..fbc3f50 --- /dev/null +++ b/mission002/js/index.js @@ -0,0 +1,78 @@ +;(async function(){ + async function fetchData(){ + const res = await fetch(APIURL) + return await res.json() + } + const data = await fetchData() + + this.data = data; + this.render = function (filteredData) { + todoList.setState(filteredData) + todoCount.render(filteredData) + todoCount.setState({ + totalCount: filteredData.length, + }) + } + this.setState = function (nextData) { + this.data = nextData; + todoList.setState(this.data) + todoCount.setState({ + totalCount: this.data.length, + }) + } + + + const $todoList = document.querySelector('.todo-list') + const $todoFilter = document.querySelector('.filters'); + const todoList = new TodoList({ + $target: $todoList, + $targetFilter: $todoFilter, + data: this.data, + onToggleClick: (index) => { + const nextData = [...this.data] + nextData[index].isCompleted = !nextData[index].isCompleted + this.setState(nextData) + }, + onRemoveClick: (index) => { + const nextData = [...this.data] + nextData.splice(index, 1) + this.setState(nextData) + }, + onFilterClick: (filterBoolean) => { + let filteredData = [...this.data] + filteredData = this.data.filter(todo => todo.isCompleted !== filterBoolean) + this.render(filteredData) + } + }); + + const $todoCount = document.querySelector('.todo-count'); + const todoCount = new TodoCount({ + $targetCount: $todoCount, + $targetFilter: $todoFilter, + data: { + totalCount: this.data.length, + }, + }) + + const $todoInput = document.querySelector('.new-todo') + const todoInput = TodoInput($todoInput, + { + onAdd: async (todoText) => { + if(todoText.length > 0){ + await fetch(APIURL,{ + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + content: todoText, + }), + }) + const updatedData = await fetchData(); + todoList.setState(updatedData) + } + } + } + ) +})() + From 4d5df1f6ad1e4abbdcda72ae25b1386510d185de Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Sat, 11 Jan 2020 18:29:26 +0900 Subject: [PATCH 10/20] =?UTF-8?q?M2=20=ED=8C=8C=EC=9D=BC=EA=B2=BD=EB=A1=9C?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission002/js/index.js | 78 ------------------------------------------ 1 file changed, 78 deletions(-) delete mode 100644 mission002/js/index.js diff --git a/mission002/js/index.js b/mission002/js/index.js deleted file mode 100644 index fbc3f50..0000000 --- a/mission002/js/index.js +++ /dev/null @@ -1,78 +0,0 @@ -;(async function(){ - async function fetchData(){ - const res = await fetch(APIURL) - return await res.json() - } - const data = await fetchData() - - this.data = data; - this.render = function (filteredData) { - todoList.setState(filteredData) - todoCount.render(filteredData) - todoCount.setState({ - totalCount: filteredData.length, - }) - } - this.setState = function (nextData) { - this.data = nextData; - todoList.setState(this.data) - todoCount.setState({ - totalCount: this.data.length, - }) - } - - - const $todoList = document.querySelector('.todo-list') - const $todoFilter = document.querySelector('.filters'); - const todoList = new TodoList({ - $target: $todoList, - $targetFilter: $todoFilter, - data: this.data, - onToggleClick: (index) => { - const nextData = [...this.data] - nextData[index].isCompleted = !nextData[index].isCompleted - this.setState(nextData) - }, - onRemoveClick: (index) => { - const nextData = [...this.data] - nextData.splice(index, 1) - this.setState(nextData) - }, - onFilterClick: (filterBoolean) => { - let filteredData = [...this.data] - filteredData = this.data.filter(todo => todo.isCompleted !== filterBoolean) - this.render(filteredData) - } - }); - - const $todoCount = document.querySelector('.todo-count'); - const todoCount = new TodoCount({ - $targetCount: $todoCount, - $targetFilter: $todoFilter, - data: { - totalCount: this.data.length, - }, - }) - - const $todoInput = document.querySelector('.new-todo') - const todoInput = TodoInput($todoInput, - { - onAdd: async (todoText) => { - if(todoText.length > 0){ - await fetch(APIURL,{ - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - content: todoText, - }), - }) - const updatedData = await fetchData(); - todoList.setState(updatedData) - } - } - } - ) -})() - From 6135ea6bbd30f483e9b2ef29607352d2ff202bd0 Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Sat, 11 Jan 2020 19:14:05 +0900 Subject: [PATCH 11/20] =?UTF-8?q?M2=20=EB=A6=AC=EB=B7=B0=20=EC=9D=BC?= =?UTF-8?q?=EB=B6=80=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 주석제거 2. 이벤트key 상수설정 3. ''로 통일 4. export 방법 수정 --- mission002/ganeodolu/js/App.js | 3 --- mission002/ganeodolu/js/TodoInput.js | 4 +++- mission002/ganeodolu/js/TodoList.js | 19 +++++++++---------- mission002/ganeodolu/js/constant.js | 10 +++++++--- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/mission002/ganeodolu/js/App.js b/mission002/ganeodolu/js/App.js index 9482857..34f12c4 100644 --- a/mission002/ganeodolu/js/App.js +++ b/mission002/ganeodolu/js/App.js @@ -5,9 +5,7 @@ import { APIURL } from './constant.js' import { fetchData } from './api.js'; export default async function app(){ - // ;(async function(){ const data = await fetchData() - const $todoList = document.querySelector('.todo-list') const $todoFilter = document.querySelector('.filters'); const todoList = new TodoList({ @@ -76,6 +74,5 @@ export default async function app(){ } } ) - // }) } diff --git a/mission002/ganeodolu/js/TodoInput.js b/mission002/ganeodolu/js/TodoInput.js index d23664c..bba89d5 100644 --- a/mission002/ganeodolu/js/TodoInput.js +++ b/mission002/ganeodolu/js/TodoInput.js @@ -1,7 +1,9 @@ +import { KEYNAME } from "./constant.js" + export default function TodoInput($targetInput, {onAdd}) { $targetInput.addEventListener('keydown', async (e) => { - if (e.key === "Enter") { + if (e.key === KEYNAME.ENTER) { await onAdd($targetInput.value) $targetInput.value = ''; } diff --git a/mission002/ganeodolu/js/TodoList.js b/mission002/ganeodolu/js/TodoList.js index f99d44f..2ae5cc7 100644 --- a/mission002/ganeodolu/js/TodoList.js +++ b/mission002/ganeodolu/js/TodoList.js @@ -9,12 +9,12 @@ export default function TodoList({ $target, $targetFilter, data, onToggleClick, this.data = nextData; this.render() } - const filterTypes = document.querySelectorAll(".filters li a") + const filterTypes = document.querySelectorAll('.filters li a') if (this === window) { throw new Error(error.NO_USED_NEW_KEYWORD) } - else if (Array.isArray(this.data) === false) { + else if (!Array.isArray(this.data)) { throw new Error(error.NOARRAY_DATA) } @@ -23,7 +23,7 @@ export default function TodoList({ $target, $targetFilter, data, onToggleClick, const { index } = e.target.parentNode.parentNode.dataset const id = await data[index]._id - if (!filterTypes[0].classList.contains("selected")) return + if (!filterTypes[0].classList.contains('selected')) return if (className === 'toggle') { onToggleClick(id) } else if (className === 'destroy') { @@ -34,11 +34,11 @@ export default function TodoList({ $target, $targetFilter, data, onToggleClick, this.$targetFilter.addEventListener('click', (e) => { const { className } = e.target; for (let val of filterTypes) { - if (val.classList.contains("selected")) { - val.classList.remove("selected") + if (val.classList.contains('selected')) { + val.classList.remove('selected') } } - e.target.classList.add("selected"); + e.target.classList.add('selected'); if (className.includes('all')) { onFilterClick() @@ -54,14 +54,13 @@ export default function TodoList({ $target, $targetFilter, data, onToggleClick, if (!val.content) { throw new Error(error.NOT_DATA) } - else if (typeof (val.content) !== "string") { + else if (typeof (val.content) !== 'string') { throw new Error(error.INVALID_DATA) } - //
  • return ` -
  • +
  • - +
    diff --git a/mission002/ganeodolu/js/constant.js b/mission002/ganeodolu/js/constant.js index 9373f2c..d238284 100644 --- a/mission002/ganeodolu/js/constant.js +++ b/mission002/ganeodolu/js/constant.js @@ -1,11 +1,15 @@ -export const error = { +const error = { NO_USED_NEW_KEYWORD: "함수 선언시 new를 사용해주세요.", NOARRAY_DATA: "data타입이 Array가 아닙니다.", NOT_DATA: "data가 null 또는 undefined 입니다.", INVALID_DATA: "data타입이 문자열이 아닙니다.", }; - +const KEYNAME = { + ENTER: "Enter", + ESC: "Escape" +} const USERNAME = 'ganeodolu'; -export const APIURL = `http://todo-api.roto.codes/${USERNAME}`; +const APIURL = `http://todo-api.roto.codes/${USERNAME}`; +export { error, KEYNAME, APIURL } From cf86464a7b21cb9d7954026f09f7caf68a82c24b Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Sat, 11 Jan 2020 20:01:56 +0900 Subject: [PATCH 12/20] =?UTF-8?q?M2=20template=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission002/ganeodolu/js/App.js | 2 +- mission002/ganeodolu/js/TodoList.js | 11 ++--------- mission002/ganeodolu/js/template.js | 11 +++++++++++ 3 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 mission002/ganeodolu/js/template.js diff --git a/mission002/ganeodolu/js/App.js b/mission002/ganeodolu/js/App.js index 34f12c4..878cbf6 100644 --- a/mission002/ganeodolu/js/App.js +++ b/mission002/ganeodolu/js/App.js @@ -2,7 +2,7 @@ import TodoList from './TodoList.js' import TodoInput from './TodoInput.js' import TodoCount from './TodoCount.js' import { APIURL } from './constant.js' -import { fetchData } from './api.js'; +import { fetchData } from './api.js' export default async function app(){ const data = await fetchData() diff --git a/mission002/ganeodolu/js/TodoList.js b/mission002/ganeodolu/js/TodoList.js index 2ae5cc7..7658dbe 100644 --- a/mission002/ganeodolu/js/TodoList.js +++ b/mission002/ganeodolu/js/TodoList.js @@ -1,4 +1,5 @@ import { error } from './constant.js' +import renderedTemplate from './template.js' export default function TodoList({ $target, $targetFilter, data, onToggleClick, onRemoveClick, onFilterClick }) { this.$target = $target; @@ -57,15 +58,7 @@ export default function TodoList({ $target, $targetFilter, data, onToggleClick, else if (typeof (val.content) !== 'string') { throw new Error(error.INVALID_DATA) } - return ` -
  • -
    - - - -
    - -
  • ` + return renderedTemplate(val, idx) }).join(''); this.$target.innerHTML = renderedHTMLText diff --git a/mission002/ganeodolu/js/template.js b/mission002/ganeodolu/js/template.js new file mode 100644 index 0000000..0e1954b --- /dev/null +++ b/mission002/ganeodolu/js/template.js @@ -0,0 +1,11 @@ +export default function renderedTemplate (val, idx) { + return ` +
  • +
    + + + +
    + +
  • ` +} \ No newline at end of file From dd00c8cfd94f396aa32d88a62e902b4c1136e101 Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Sat, 11 Jan 2020 21:36:34 +0900 Subject: [PATCH 13/20] =?UTF-8?q?M2=20=EC=99=84=EB=A3=8C,=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 통일된 메서드명으로 변경 2. 버튼 className확인시 swith문 사용 3. 불완전했던 할일 추가 뒤 완료, 삭제 기능 수정 --- mission002/ganeodolu/js/App.js | 6 +++--- mission002/ganeodolu/js/TodoList.js | 20 ++++++++++---------- mission002/ganeodolu/js/template.js | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mission002/ganeodolu/js/App.js b/mission002/ganeodolu/js/App.js index 878cbf6..634eeea 100644 --- a/mission002/ganeodolu/js/App.js +++ b/mission002/ganeodolu/js/App.js @@ -12,7 +12,7 @@ export default async function app(){ $target: $todoList, $targetFilter: $todoFilter, data: data, - onToggleClick: async (id) => { + onClickToggle: async (id) => { await fetch(`${APIURL}/${id}/toggle`, { method: "PUT", }) @@ -22,7 +22,7 @@ export default async function app(){ totalCount: updatedData.length }) }, - onRemoveClick: async (id) => { + onClickRemoval: async (id) => { await fetch(`${APIURL}/${id}`, { method: 'DELETE' }) @@ -32,7 +32,7 @@ export default async function app(){ totalCount: updatedData.length }) }, - onFilterClick: (filterBoolean) => { + onClickFilter: (filterBoolean) => { let filteredData = [...data] filteredData = data.filter(todo => todo.isCompleted !== filterBoolean) todoList.setState(filteredData) diff --git a/mission002/ganeodolu/js/TodoList.js b/mission002/ganeodolu/js/TodoList.js index 7658dbe..6c10e48 100644 --- a/mission002/ganeodolu/js/TodoList.js +++ b/mission002/ganeodolu/js/TodoList.js @@ -1,7 +1,7 @@ import { error } from './constant.js' import renderedTemplate from './template.js' -export default function TodoList({ $target, $targetFilter, data, onToggleClick, onRemoveClick, onFilterClick }) { +export default function TodoList({ $target, $targetFilter, data, onClickToggle, onClickRemoval, onClickFilter }) { this.$target = $target; this.$targetFilter = $targetFilter this.data = data; @@ -22,13 +22,13 @@ export default function TodoList({ $target, $targetFilter, data, onToggleClick, this.$target.addEventListener('click', async (e) => { const { className } = e.target; const { index } = e.target.parentNode.parentNode.dataset - - const id = await data[index]._id + const id = this.data[index]._id if (!filterTypes[0].classList.contains('selected')) return - if (className === 'toggle') { - onToggleClick(id) - } else if (className === 'destroy') { - onRemoveClick(id) + switch (className){ + case 'toggle': await onClickToggle(id) + break; + case 'destroy': await onClickRemoval(id) + break; } }) @@ -42,11 +42,11 @@ export default function TodoList({ $target, $targetFilter, data, onToggleClick, e.target.classList.add('selected'); if (className.includes('all')) { - onFilterClick() + onClickFilter() } else if (className.includes('active')) { - onFilterClick(true) + onClickFilter(true) } else if (className.includes('completed')) { - onFilterClick(false) + onClickFilter(false) } }) diff --git a/mission002/ganeodolu/js/template.js b/mission002/ganeodolu/js/template.js index 0e1954b..9310dde 100644 --- a/mission002/ganeodolu/js/template.js +++ b/mission002/ganeodolu/js/template.js @@ -1,4 +1,4 @@ -export default function renderedTemplate (val, idx) { +export default function renderedTemplate(val, idx) { return `
  • From 04b644d72275c5bf6a2aecbb86d11f5de113c2f6 Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Mon, 13 Jan 2020 18:19:11 +0900 Subject: [PATCH 14/20] =?UTF-8?q?M3=20=EB=A6=AC=EB=B7=B0=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. template분리 2. 주석제거 --- mission002/ganeodolu/index.html | 24 ------------------------ mission002/ganeodolu/js/TodoCount.js | 4 +++- mission002/ganeodolu/js/TodoList.js | 8 ++++---- mission002/ganeodolu/js/template.js | 27 +++++++++++++++++---------- 4 files changed, 24 insertions(+), 39 deletions(-) diff --git a/mission002/ganeodolu/index.html b/mission002/ganeodolu/index.html index d689139..37c6c0e 100644 --- a/mission002/ganeodolu/index.html +++ b/mission002/ganeodolu/index.html @@ -15,30 +15,6 @@

    TODOS

      -
    • -
      - -
      - -
    • -
    • -
      - - - -
      - -
    • -
    • -
      - - - -
      - -
    diff --git a/mission002/ganeodolu/js/TodoCount.js b/mission002/ganeodolu/js/TodoCount.js index 7b8635f..4d60b44 100644 --- a/mission002/ganeodolu/js/TodoCount.js +++ b/mission002/ganeodolu/js/TodoCount.js @@ -1,3 +1,5 @@ +import { totalCountTemplate } from './template.js' + export default function TodoCount({$targetCount, $targetFilter, data, onFilterClick}) { this.data = data; this.$targetCount = $targetCount; @@ -14,7 +16,7 @@ export default function TodoCount({$targetCount, $targetFilter, data, onFilterCl this.render = function () { const { totalCount } = this.data - $targetCount.innerHTML = `총 ${totalCount}개` + $targetCount.innerHTML = totalCountTemplate(totalCount) } this.render(); diff --git a/mission002/ganeodolu/js/TodoList.js b/mission002/ganeodolu/js/TodoList.js index 6c10e48..cf78da2 100644 --- a/mission002/ganeodolu/js/TodoList.js +++ b/mission002/ganeodolu/js/TodoList.js @@ -1,5 +1,5 @@ import { error } from './constant.js' -import renderedTemplate from './template.js' +import { renderedTemplate } from './template.js' export default function TodoList({ $target, $targetFilter, data, onClickToggle, onClickRemoval, onClickFilter }) { this.$target = $target; @@ -24,11 +24,11 @@ export default function TodoList({ $target, $targetFilter, data, onClickToggle, const { index } = e.target.parentNode.parentNode.dataset const id = this.data[index]._id if (!filterTypes[0].classList.contains('selected')) return - switch (className){ + switch (className) { case 'toggle': await onClickToggle(id) - break; + break; case 'destroy': await onClickRemoval(id) - break; + break; } }) diff --git a/mission002/ganeodolu/js/template.js b/mission002/ganeodolu/js/template.js index 9310dde..91d0db2 100644 --- a/mission002/ganeodolu/js/template.js +++ b/mission002/ganeodolu/js/template.js @@ -1,11 +1,18 @@ -export default function renderedTemplate(val, idx) { +function renderedTemplate(val, idx) { return ` -
  • -
    - - - -
    - -
  • ` -} \ No newline at end of file +
  • +
    + + + +
    + +
  • ` +} + +function totalCountTemplate(totalCount){ + return `총 ${totalCount}개` + +} + +export { renderedTemplate, totalCountTemplate } \ No newline at end of file From 3d7ed1505561b69f361fc1ee49c069cf4b12be22 Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Wed, 15 Jan 2020 17:24:09 +0900 Subject: [PATCH 15/20] =?UTF-8?q?M3=20=EB=A6=AC=EB=B7=B0=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit data 전개연산자 삭제 --- mission002/ganeodolu/js/App.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mission002/ganeodolu/js/App.js b/mission002/ganeodolu/js/App.js index 634eeea..0763866 100644 --- a/mission002/ganeodolu/js/App.js +++ b/mission002/ganeodolu/js/App.js @@ -33,7 +33,7 @@ export default async function app(){ }) }, onClickFilter: (filterBoolean) => { - let filteredData = [...data] + let filteredData = data; filteredData = data.filter(todo => todo.isCompleted !== filterBoolean) todoList.setState(filteredData) todoCount.setState({ From a9d2d5d7160a071aef974e97a64e184dec254d4b Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Wed, 15 Jan 2020 17:53:01 +0900 Subject: [PATCH 16/20] =?UTF-8?q?M3=20=EB=A6=AC=EB=B7=B0=EB=B0=98=EC=98=81?= =?UTF-8?q?=20App=20=EC=95=9E=EC=97=90=20async=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission002/ganeodolu/js/App.js | 6 +++++- mission002/ganeodolu/js/index.js | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/mission002/ganeodolu/js/App.js b/mission002/ganeodolu/js/App.js index 0763866..12bcb5a 100644 --- a/mission002/ganeodolu/js/App.js +++ b/mission002/ganeodolu/js/App.js @@ -4,7 +4,8 @@ import TodoCount from './TodoCount.js' import { APIURL } from './constant.js' import { fetchData } from './api.js' -export default async function app(){ +export default function App(){ + ;(async function(){ const data = await fetchData() const $todoList = document.querySelector('.todo-list') const $todoFilter = document.querySelector('.filters'); @@ -74,5 +75,8 @@ export default async function app(){ } } ) + + })() + } diff --git a/mission002/ganeodolu/js/index.js b/mission002/ganeodolu/js/index.js index ea49186..85a190c 100644 --- a/mission002/ganeodolu/js/index.js +++ b/mission002/ganeodolu/js/index.js @@ -1,2 +1,2 @@ import app from './App.js' -app() +new App() From 02d5ddebecf4313adda479e8b1a9a6b231a109cf Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Wed, 15 Jan 2020 18:06:05 +0900 Subject: [PATCH 17/20] =?UTF-8?q?M3=20app=EC=9D=84=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9E=90=EC=97=90=EC=84=9C=20=ED=95=A8=EC=88=98=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this를 사용하지 않아서 new로 선언할 이유가 없음 --- mission002/ganeodolu/js/App.js | 2 +- mission002/ganeodolu/js/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mission002/ganeodolu/js/App.js b/mission002/ganeodolu/js/App.js index 12bcb5a..6417329 100644 --- a/mission002/ganeodolu/js/App.js +++ b/mission002/ganeodolu/js/App.js @@ -4,7 +4,7 @@ import TodoCount from './TodoCount.js' import { APIURL } from './constant.js' import { fetchData } from './api.js' -export default function App(){ +export default function app(){ ;(async function(){ const data = await fetchData() const $todoList = document.querySelector('.todo-list') diff --git a/mission002/ganeodolu/js/index.js b/mission002/ganeodolu/js/index.js index 85a190c..ea49186 100644 --- a/mission002/ganeodolu/js/index.js +++ b/mission002/ganeodolu/js/index.js @@ -1,2 +1,2 @@ import app from './App.js' -new App() +app() From f172694e41f1a04b7744724775e5dbf2bcf4b634 Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Thu, 16 Jan 2020 16:39:36 +0900 Subject: [PATCH 18/20] =?UTF-8?q?M3=20localstrage=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. closest사용 2. 오프라인시 화면에 표시 API핸들러 만들면서 토글 및 삭제 불안정 --- mission002/ganeodolu/index.html | 3 ++ mission002/ganeodolu/js/App.js | 47 ++++++++++++++++++++++------ mission002/ganeodolu/js/TodoCount.js | 2 +- mission002/ganeodolu/js/TodoList.js | 10 +++--- mission002/ganeodolu/js/api.js | 35 ++++++++++++++++++--- mission002/ganeodolu/js/index.js | 2 +- mission002/ganeodolu/js/template.js | 3 +- 7 files changed, 79 insertions(+), 23 deletions(-) diff --git a/mission002/ganeodolu/index.html b/mission002/ganeodolu/index.html index 37c6c0e..014e175 100644 --- a/mission002/ganeodolu/index.html +++ b/mission002/ganeodolu/index.html @@ -29,6 +29,9 @@

    TODOS

  • 완료한 일
  • +
  • + +
  • diff --git a/mission002/ganeodolu/js/App.js b/mission002/ganeodolu/js/App.js index 6417329..27dd722 100644 --- a/mission002/ganeodolu/js/App.js +++ b/mission002/ganeodolu/js/App.js @@ -1,12 +1,35 @@ import TodoList from './TodoList.js' import TodoInput from './TodoInput.js' import TodoCount from './TodoCount.js' -import { APIURL } from './constant.js' -import { fetchData } from './api.js' +import { APIURL } from './constant.js' +import { fetchData, methods } from './api.js' + +export default function app() { + async function getData(){ + if (navigator.onLine) { + return await fetchData() + } else { + return JSON.parse(localStorage.getItem('todoItems')) + } + } + const $networkDisplay = document.querySelector('.network-display') + window.addEventListener("offline", function () { + console.log('offline') + $networkDisplay.classList.remove('hidden') + }); + window.addEventListener("online", function () { + console.log('online') + $networkDisplay.classList.add('hidden') + }); + + ; (async function () { + const data = await getData() + + function saveLocalStorage(data) { + localStorage.setItem('todoItems', JSON.stringify(data)) + } + saveLocalStorage(data) -export default function app(){ - ;(async function(){ - const data = await fetchData() const $todoList = document.querySelector('.todo-list') const $todoFilter = document.querySelector('.filters'); const todoList = new TodoList({ @@ -14,14 +37,14 @@ export default function app(){ $targetFilter: $todoFilter, data: data, onClickToggle: async (id) => { - await fetch(`${APIURL}/${id}/toggle`, { - method: "PUT", - }) + const isUpdated = await methods.put(id) const updatedData = await fetchData() todoList.setState(updatedData) todoCount.setState({ totalCount: updatedData.length }) + saveLocalStorage(updatedData) + }, onClickRemoval: async (id) => { await fetch(`${APIURL}/${id}`, { @@ -32,6 +55,8 @@ export default function app(){ todoCount.setState({ totalCount: updatedData.length }) + saveLocalStorage(updatedData) + }, onClickFilter: (filterBoolean) => { let filteredData = data; @@ -42,7 +67,7 @@ export default function app(){ }) } }); - + const $todoCount = document.querySelector('.todo-count'); const todoCount = new TodoCount({ $targetCount: $todoCount, @@ -51,7 +76,7 @@ export default function app(){ totalCount: data.length, }, }) - + const $todoInput = document.querySelector('.new-todo') const todoInput = TodoInput($todoInput, { @@ -71,6 +96,8 @@ export default function app(){ todoCount.setState({ totalCount: updatedData.length }) + saveLocalStorage(updatedData) + } } } diff --git a/mission002/ganeodolu/js/TodoCount.js b/mission002/ganeodolu/js/TodoCount.js index 4d60b44..efdeacc 100644 --- a/mission002/ganeodolu/js/TodoCount.js +++ b/mission002/ganeodolu/js/TodoCount.js @@ -1,6 +1,6 @@ import { totalCountTemplate } from './template.js' -export default function TodoCount({$targetCount, $targetFilter, data, onFilterClick}) { +export default function TodoCount({$targetCount, $targetFilter, data}) { this.data = data; this.$targetCount = $targetCount; this.$targetFilter = $targetFilter; diff --git a/mission002/ganeodolu/js/TodoList.js b/mission002/ganeodolu/js/TodoList.js index cf78da2..02a01fc 100644 --- a/mission002/ganeodolu/js/TodoList.js +++ b/mission002/ganeodolu/js/TodoList.js @@ -19,15 +19,16 @@ export default function TodoList({ $target, $targetFilter, data, onClickToggle, throw new Error(error.NOARRAY_DATA) } - this.$target.addEventListener('click', async (e) => { + this.$target.addEventListener('click', (e) => { const { className } = e.target; - const { index } = e.target.parentNode.parentNode.dataset + const index = e.target.closest('div li').dataset.index const id = this.data[index]._id + if (!filterTypes[0].classList.contains('selected')) return switch (className) { - case 'toggle': await onClickToggle(id) + case 'toggle': onClickToggle(id) break; - case 'destroy': await onClickRemoval(id) + case 'destroy': onClickRemoval(id) break; } }) @@ -63,5 +64,6 @@ export default function TodoList({ $target, $targetFilter, data, onClickToggle, this.$target.innerHTML = renderedHTMLText } + this.render() } \ No newline at end of file diff --git a/mission002/ganeodolu/js/api.js b/mission002/ganeodolu/js/api.js index ec6e4b3..9edf3da 100644 --- a/mission002/ganeodolu/js/api.js +++ b/mission002/ganeodolu/js/api.js @@ -1,6 +1,31 @@ -import { APIURL } from './constant.js' +import { APIURL } from './constant.js' -export async function fetchData() { - const res = await fetch(APIURL) - return await res.json() -} \ No newline at end of file +const methods = { + get() { + return fetch(APIURL) + }, + put(id) { + fetch(`${APIURL}/${id}/toggle`, { + method: 'PUT', + }) + }, + post(todoText) { + fetch(APIURL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + content: todoText, + }), + }) + }, + delete(id) { + fetch(`${APIURL}/${id}`, { + method: 'DELETE', + }) + } +} + +const fetchData = async () => await methods.get().then(res => res.json()) +export { fetchData, methods } \ No newline at end of file diff --git a/mission002/ganeodolu/js/index.js b/mission002/ganeodolu/js/index.js index ea49186..1af7b91 100644 --- a/mission002/ganeodolu/js/index.js +++ b/mission002/ganeodolu/js/index.js @@ -1,2 +1,2 @@ import app from './App.js' -app() +new app() diff --git a/mission002/ganeodolu/js/template.js b/mission002/ganeodolu/js/template.js index 91d0db2..c408fc4 100644 --- a/mission002/ganeodolu/js/template.js +++ b/mission002/ganeodolu/js/template.js @@ -1,6 +1,6 @@ function renderedTemplate(val, idx) { return ` -
  • +
  • @@ -12,7 +12,6 @@ function renderedTemplate(val, idx) { function totalCountTemplate(totalCount){ return `총 ${totalCount}개` - } export { renderedTemplate, totalCountTemplate } \ No newline at end of file From e58b6e9826d60bfba454afcf28f3fde2a3377d11 Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Sat, 15 Feb 2020 22:57:33 +0900 Subject: [PATCH 19/20] =?UTF-8?q?M2=20api=20=EB=A9=94=EC=86=8C=EB=93=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission002/ganeodolu/index.html | 61 ++++---- mission002/ganeodolu/js/App.js | 207 +++++++++++++++------------ mission002/ganeodolu/js/TodoInput.js | 8 +- mission002/ganeodolu/js/TodoList.js | 20 ++- mission002/ganeodolu/js/api.js | 76 ++++++---- mission002/ganeodolu/js/constant.js | 4 +- 6 files changed, 224 insertions(+), 152 deletions(-) diff --git a/mission002/ganeodolu/index.html b/mission002/ganeodolu/index.html index 014e175..e5efcb3 100644 --- a/mission002/ganeodolu/index.html +++ b/mission002/ganeodolu/index.html @@ -1,40 +1,43 @@ + Fetch - TODOS + -
    -
    -

    TODOS

    - -
    -
    - -
      -
    -
    -
    - 0 - -
    -
    - +
    +
    +

    TODOS

    + +
    +
    + +
      +
    +
    +
    + 0 + +
    +
    + + diff --git a/mission002/ganeodolu/js/App.js b/mission002/ganeodolu/js/App.js index 27dd722..13a303c 100644 --- a/mission002/ganeodolu/js/App.js +++ b/mission002/ganeodolu/js/App.js @@ -2,108 +2,139 @@ import TodoList from './TodoList.js' import TodoInput from './TodoInput.js' import TodoCount from './TodoCount.js' import { APIURL } from './constant.js' -import { fetchData, methods } from './api.js' +// import { fetchData, methods } from './api.js' +import { apiHandler } from './api.js' export default function app() { - async function getData(){ - if (navigator.onLine) { - return await fetchData() - } else { - return JSON.parse(localStorage.getItem('todoItems')) - } - } - const $networkDisplay = document.querySelector('.network-display') - window.addEventListener("offline", function () { - console.log('offline') - $networkDisplay.classList.remove('hidden') - }); - window.addEventListener("online", function () { - console.log('online') - $networkDisplay.classList.add('hidden') - }); - - ; (async function () { - const data = await getData() + // async function getData(){ + // if (navigator.onLine) { + // return await fetchData() + // } else { + // return JSON.parse(localStorage.getItem('todoItems')) + // } + // } + // const $networkDisplay = document.querySelector('.network-display') + // window.addEventListener("offline", function () { + // console.log('offline') + // $networkDisplay.classList.remove('hidden') + // }); + // window.addEventListener("online", function () { + // console.log('online') + // $networkDisplay.classList.add('hidden') + // }); - function saveLocalStorage(data) { - localStorage.setItem('todoItems', JSON.stringify(data)) - } - saveLocalStorage(data) + // window.addEventListener('load', async (e) => { + // const data = await apiHandler({}) + // console.log(data) + // }) - const $todoList = document.querySelector('.todo-list') - const $todoFilter = document.querySelector('.filters'); - const todoList = new TodoList({ - $target: $todoList, - $targetFilter: $todoFilter, - data: data, - onClickToggle: async (id) => { - const isUpdated = await methods.put(id) - const updatedData = await fetchData() - todoList.setState(updatedData) - todoCount.setState({ - totalCount: updatedData.length - }) - saveLocalStorage(updatedData) - }, - onClickRemoval: async (id) => { - await fetch(`${APIURL}/${id}`, { - method: 'DELETE' + // ; (async function () { + // const data = await getData() + + // function saveLocalStorage(data) { + // localStorage.setItem('todoItems', JSON.stringify(data)) + // } + // saveLocalStorage(data) + const $todoFilter = document.querySelector('.filters'); + + const $todoCount = document.querySelector('.todo-count'); + const todoCount = new TodoCount({ + $targetCount: $todoCount, + $targetFilter: $todoFilter, + data: { + totalCount: [], + }, + }) + + const $todoList = document.querySelector('.todo-list') + const todoList = new TodoList({ + $target: $todoList, + $targetFilter: $todoFilter, + data: [], + onLoad: async () => { + const data = await apiHandler({}) + todoList.setState(data) + todoCount.setState({ + totalCount: data.length + }) + // saveLocalStorage(data) + }, + onClickToggle: async (id) => { + // const isUpdated = await methods.put(id) + const isUpdated = await apiHandler({ + method: 'PUT', + customUrl: `${id}/toggle` + }) + const updatedData = await apiHandler({}) + todoList.setState(updatedData) + todoCount.setState({ + totalCount: updatedData.length + }) + // saveLocalStorage(updatedData) + + }, + onClickRemoval: async (id) => { + const isUpdated = await apiHandler({ + method: 'DELETE', + customUrl: id + }) + const updatedData = await apiHandler({}) + todoList.setState(updatedData) + todoCount.setState({ + totalCount: updatedData.length + }) + // saveLocalStorage(updatedData) + + }, + onClickFilter: (filterBoolean) => { + let filteredData = data; + filteredData = data.filter(todo => todo.isCompleted !== filterBoolean) + todoList.setState(filteredData) + todoCount.setState({ + totalCount: filteredData.length + }) + } + }); + const $todoInput = document.querySelector('.new-todo') + const todoInput = TodoInput($todoInput, + { + onAdd: async (todoText) => { + const isUpdated = await apiHandler({ + method: 'POST', + body: JSON.stringify({ + content: todoText, + }) }) - const updatedData = await fetchData() + const updatedData = await apiHandler({}) todoList.setState(updatedData) todoCount.setState({ totalCount: updatedData.length }) - saveLocalStorage(updatedData) + // onAdd: async (todoText) => { + // if (todoText.length > 0) { + // await fetch(APIURL, { + // method: 'POST', + // headers: { + // 'Content-Type': 'application/json', + // }, + // body: JSON.stringify({ + // content: todoText, + // }), + // }) + // const updatedData = await fetchData(); + // todoList.setState(updatedData) + // todoCount.setState({ + // totalCount: updatedData.length + // }) + // saveLocalStorage(updatedData) - }, - onClickFilter: (filterBoolean) => { - let filteredData = data; - filteredData = data.filter(todo => todo.isCompleted !== filterBoolean) - todoList.setState(filteredData) - todoCount.setState({ - totalCount: filteredData.length - }) + // } + // } } - }); - - const $todoCount = document.querySelector('.todo-count'); - const todoCount = new TodoCount({ - $targetCount: $todoCount, - $targetFilter: $todoFilter, - data: { - totalCount: data.length, - }, }) - const $todoInput = document.querySelector('.new-todo') - const todoInput = TodoInput($todoInput, - { - onAdd: async (todoText) => { - if (todoText.length > 0) { - await fetch(APIURL, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - content: todoText, - }), - }) - const updatedData = await fetchData(); - todoList.setState(updatedData) - todoCount.setState({ - totalCount: updatedData.length - }) - saveLocalStorage(updatedData) - - } - } - } - ) - - })() + // })() } diff --git a/mission002/ganeodolu/js/TodoInput.js b/mission002/ganeodolu/js/TodoInput.js index bba89d5..d6ea774 100644 --- a/mission002/ganeodolu/js/TodoInput.js +++ b/mission002/ganeodolu/js/TodoInput.js @@ -1,10 +1,10 @@ import { KEYNAME } from "./constant.js" -export default function TodoInput($targetInput, {onAdd}) { - +export default function TodoInput($targetInput, { onAdd }) { + $targetInput.addEventListener('keydown', async (e) => { - if (e.key === KEYNAME.ENTER) { - await onAdd($targetInput.value) + if (e.key === KEYNAME.ENTER && $targetInput.value) { + await onAdd($targetInput.value) $targetInput.value = ''; } }) diff --git a/mission002/ganeodolu/js/TodoList.js b/mission002/ganeodolu/js/TodoList.js index 02a01fc..377a691 100644 --- a/mission002/ganeodolu/js/TodoList.js +++ b/mission002/ganeodolu/js/TodoList.js @@ -1,7 +1,17 @@ import { error } from './constant.js' import { renderedTemplate } from './template.js' -export default function TodoList({ $target, $targetFilter, data, onClickToggle, onClickRemoval, onClickFilter }) { +export default function TodoList( + { + $target, + $targetFilter, + data, + onLoad, + onClickToggle, + onClickRemoval, + onClickFilter + }) +{ this.$target = $target; this.$targetFilter = $targetFilter this.data = data; @@ -19,6 +29,11 @@ export default function TodoList({ $target, $targetFilter, data, onClickToggle, throw new Error(error.NOARRAY_DATA) } + window.addEventListener('load', async (e) => { + // const data = await apiHandler({}) + onLoad() + }) + this.$target.addEventListener('click', (e) => { const { className } = e.target; const index = e.target.closest('div li').dataset.index @@ -52,9 +67,10 @@ export default function TodoList({ $target, $targetFilter, data, onClickToggle, }) this.render = function () { + console.log(this.data) const renderedHTMLText = this.data.map((val, idx) => { if (!val.content) { - throw new Error(error.NOT_DATA) + // throw new Error(error.NOT_DATA) } else if (typeof (val.content) !== 'string') { throw new Error(error.INVALID_DATA) diff --git a/mission002/ganeodolu/js/api.js b/mission002/ganeodolu/js/api.js index 9edf3da..3ddc4cd 100644 --- a/mission002/ganeodolu/js/api.js +++ b/mission002/ganeodolu/js/api.js @@ -1,31 +1,53 @@ -import { APIURL } from './constant.js' +import { USERNAME, APIURL } from './constant.js' -const methods = { - get() { - return fetch(APIURL) - }, - put(id) { - fetch(`${APIURL}/${id}/toggle`, { - method: 'PUT', - }) - }, - post(todoText) { - fetch(APIURL, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - content: todoText, - }), - }) - }, - delete(id) { - fetch(`${APIURL}/${id}`, { - method: 'DELETE', - }) +const apiHandler = async ({ method, body, customUrl }) => { + const options = { + method, + headers: { + 'Content-Type': 'application/json', + }, + body + } + try { + const res = await fetch(`${APIURL}/${USERNAME}${customUrl ? `/${customUrl}` : ''}`, options) + if (res.ok){ + const data = await res.json() + return data + } + } catch(error) { + throw new Error(error) } } -const fetchData = async () => await methods.get().then(res => res.json()) -export { fetchData, methods } \ No newline at end of file + +// const methods = { +// get() { +// return fetch(APIURL) +// }, +// put(id) { +// fetch(`${APIURL}/${id}/toggle`, { +// method: 'PUT', +// }) +// }, +// post(todoText) { +// fetch(APIURL, { +// method: 'POST', +// headers: { +// 'Content-Type': 'application/json', +// }, +// body: JSON.stringify({ +// content: todoText, +// }), +// }) +// }, +// delete(id) { +// fetch(`${APIURL}/${id}`, { +// method: 'DELETE', +// }) +// } +// } + +// const fetchData = async () => await methods.get().then(res => res.json()) +// export { fetchData, methods } + +export { apiHandler } \ No newline at end of file diff --git a/mission002/ganeodolu/js/constant.js b/mission002/ganeodolu/js/constant.js index d238284..6b7920d 100644 --- a/mission002/ganeodolu/js/constant.js +++ b/mission002/ganeodolu/js/constant.js @@ -10,6 +10,6 @@ const KEYNAME = { } const USERNAME = 'ganeodolu'; -const APIURL = `http://todo-api.roto.codes/${USERNAME}`; +const APIURL = `http://todo-api.roto.codes`; -export { error, KEYNAME, APIURL } +export { error, KEYNAME, APIURL, USERNAME } From 6551100a9e18fe519419cdc2d09a13d64989b1c9 Mon Sep 17 00:00:00 2001 From: ganeodolu Date: Sun, 16 Feb 2020 16:09:14 +0900 Subject: [PATCH 20/20] =?UTF-8?q?M2=20localstorage=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 필터선택후 토글 및 삭제는 안됨 --- mission002/ganeodolu/index.html | 2 +- mission002/ganeodolu/js/App.js | 98 ++++++++++------------------- mission002/ganeodolu/js/TodoList.js | 3 +- mission002/ganeodolu/js/template.js | 2 +- 4 files changed, 35 insertions(+), 70 deletions(-) diff --git a/mission002/ganeodolu/index.html b/mission002/ganeodolu/index.html index e5efcb3..a960759 100644 --- a/mission002/ganeodolu/index.html +++ b/mission002/ganeodolu/index.html @@ -32,7 +32,7 @@

    TODOS

    완료한 일
  • - +
  • diff --git a/mission002/ganeodolu/js/App.js b/mission002/ganeodolu/js/App.js index 13a303c..61945b6 100644 --- a/mission002/ganeodolu/js/App.js +++ b/mission002/ganeodolu/js/App.js @@ -1,43 +1,34 @@ import TodoList from './TodoList.js' import TodoInput from './TodoInput.js' import TodoCount from './TodoCount.js' -import { APIURL } from './constant.js' -// import { fetchData, methods } from './api.js' import { apiHandler } from './api.js' export default function app() { - // async function getData(){ - // if (navigator.onLine) { - // return await fetchData() - // } else { - // return JSON.parse(localStorage.getItem('todoItems')) - // } - // } - // const $networkDisplay = document.querySelector('.network-display') - // window.addEventListener("offline", function () { - // console.log('offline') - // $networkDisplay.classList.remove('hidden') - // }); - // window.addEventListener("online", function () { - // console.log('online') - // $networkDisplay.classList.add('hidden') - // }); - // window.addEventListener('load', async (e) => { - // const data = await apiHandler({}) - // console.log(data) - // }) + function getData() { + if (navigator.onLine) { + return apiHandler({}) + } else { + return JSON.parse(localStorage.getItem('todoItems')) + } + } + function saveLocalStorage(data) { + localStorage.setItem('todoItems', JSON.stringify(data)) + } - // ; (async function () { - // const data = await getData() + const $networkDisplay = document.querySelector('.network-display') - // function saveLocalStorage(data) { - // localStorage.setItem('todoItems', JSON.stringify(data)) - // } - // saveLocalStorage(data) - const $todoFilter = document.querySelector('.filters'); + window.addEventListener("offline", function () { + console.log('offline') + $networkDisplay.classList.remove('hidden') + }); + window.addEventListener("online", function () { + console.log('online') + $networkDisplay.classList.add('hidden') + }); + const $todoFilter = document.querySelector('.filters'); const $todoCount = document.querySelector('.todo-count'); const todoCount = new TodoCount({ $targetCount: $todoCount, @@ -53,43 +44,41 @@ export default function app() { $targetFilter: $todoFilter, data: [], onLoad: async () => { - const data = await apiHandler({}) + const data = await getData() todoList.setState(data) todoCount.setState({ totalCount: data.length }) - // saveLocalStorage(data) + saveLocalStorage(data) }, onClickToggle: async (id) => { - // const isUpdated = await methods.put(id) const isUpdated = await apiHandler({ method: 'PUT', customUrl: `${id}/toggle` }) - const updatedData = await apiHandler({}) + const updatedData = await getData() todoList.setState(updatedData) todoCount.setState({ totalCount: updatedData.length }) - // saveLocalStorage(updatedData) - + saveLocalStorage(updatedData) }, onClickRemoval: async (id) => { const isUpdated = await apiHandler({ method: 'DELETE', customUrl: id }) - const updatedData = await apiHandler({}) + const updatedData = await getData() todoList.setState(updatedData) todoCount.setState({ totalCount: updatedData.length }) - // saveLocalStorage(updatedData) - + saveLocalStorage(updatedData) }, - onClickFilter: (filterBoolean) => { - let filteredData = data; - filteredData = data.filter(todo => todo.isCompleted !== filterBoolean) + onClickFilter: async (filterBoolean) => { + // let filteredData = data; + const data = await getData() + let filteredData = data.filter(todo => todo.isCompleted !== filterBoolean) todoList.setState(filteredData) todoCount.setState({ totalCount: filteredData.length @@ -106,35 +95,12 @@ export default function app() { content: todoText, }) }) - const updatedData = await apiHandler({}) + const updatedData = await getData() todoList.setState(updatedData) todoCount.setState({ totalCount: updatedData.length }) - // onAdd: async (todoText) => { - // if (todoText.length > 0) { - // await fetch(APIURL, { - // method: 'POST', - // headers: { - // 'Content-Type': 'application/json', - // }, - // body: JSON.stringify({ - // content: todoText, - // }), - // }) - // const updatedData = await fetchData(); - // todoList.setState(updatedData) - // todoCount.setState({ - // totalCount: updatedData.length - // }) - // saveLocalStorage(updatedData) - - // } - // } + saveLocalStorage(updatedData) } }) - - // })() - } - diff --git a/mission002/ganeodolu/js/TodoList.js b/mission002/ganeodolu/js/TodoList.js index 377a691..91dbf44 100644 --- a/mission002/ganeodolu/js/TodoList.js +++ b/mission002/ganeodolu/js/TodoList.js @@ -29,7 +29,7 @@ export default function TodoList( throw new Error(error.NOARRAY_DATA) } - window.addEventListener('load', async (e) => { + window.addEventListener('load', (e) => { // const data = await apiHandler({}) onLoad() }) @@ -67,7 +67,6 @@ export default function TodoList( }) this.render = function () { - console.log(this.data) const renderedHTMLText = this.data.map((val, idx) => { if (!val.content) { // throw new Error(error.NOT_DATA) diff --git a/mission002/ganeodolu/js/template.js b/mission002/ganeodolu/js/template.js index c408fc4..83a8fa2 100644 --- a/mission002/ganeodolu/js/template.js +++ b/mission002/ganeodolu/js/template.js @@ -11,7 +11,7 @@ function renderedTemplate(val, idx) { } function totalCountTemplate(totalCount){ - return `총 ${totalCount}개` + return `총 ${totalCount} 개` } export { renderedTemplate, totalCountTemplate } \ No newline at end of file