Skip to content

[10기 이재훈] ToDoList CRUD #213

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@

## 🎯 요구사항

- [ ] todo list에 todoItem을 키보드로 입력하여 추가하기
- [ ] todo list의 체크박스를 클릭하여 complete 상태로 변경 (li tag 에 completed class 추가, input 태그에 checked 속성 추가)
- [ ] todo list의 x버튼을 이용해서 해당 엘리먼트를 삭제
- [x] todo list에 todoItem을 키보드로 입력하여 추가하기
- [x] todo list의 체크박스를 클릭하여 complete 상태로 변경 (li tag 에 completed class 추가, input 태그에 checked 속성 추가)
- [x] todo list의 x버튼을 이용해서 해당 엘리먼트를 삭제
- [ ] todo list를 더블클릭했을 때 input 모드로 변경 (li tag 에 editing class 추가) 단 이때 수정을 완료하지 않은 상태에서 esc키를 누르면 수정되지 않은 채로 다시 view 모드로 복귀
- [ ] todo list의 item갯수를 count한 갯수를 리스트의 하단에 보여주기
- [ ] todo list의 상태값을 확인하여, 해야할 일과, 완료한 일을 클릭하면 해당 상태의 아이템만 보여주기
Expand Down
File renamed without changes.
7 changes: 4 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<!DOCTYPE html>
<html lang="kr">
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>이벤트 - TODOS</title>
<link rel="stylesheet" href="./src/css/style.css" />
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<div class="todoapp">
Expand All @@ -22,7 +22,7 @@ <h1>TODOS</h1>
<span class="todo-count">총 <strong>0</strong> 개</span>
<ul class="filters">
<li>
<a class="all selected" href="#">전체보기</a>
<a class="all selected" href="/#">전체보기</a>
</li>
<li>
<a class="active" href="#active">해야할 일</a>
Expand All @@ -34,5 +34,6 @@ <h1>TODOS</h1>
</div>
</main>
</div>
<script src="./src/App.js" type="module"></script>
</body>
</html>
18 changes: 18 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ToDoInput,ToDoList } from "./component/index.js";
class App {
$todoInput;
$todoList;
constructor(){
const toDoInputTarget = document.querySelector("#new-todo-title");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반복되는 document.querySelector를 유틸함수로 빼서 재사용해보는것도 좋을꺼 같아요.

const toDoListTarget = document.querySelector('#todo-list');
this.$todoInput = new ToDoInput(toDoInputTarget,{
addToDoItem: itemTitle => this.addToDoItem(itemTitle)
});
this.$todoList = new ToDoList(toDoListTarget);
}
addToDoItem(itemTitle){
this.$todoList.addItem(itemTitle);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todoList와 todoInput이 강하게 묶여 있습니다. observer 패턴형태를 참고해서 수정해도 좋을꺼 같습니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵넵 todoList 와 todoInput을 상위에서 묶음으로써 todoList 컴포넌트와 todoInput 컴포넌트의 state를 따로 관리하였고, 그로인해서 state 초기화가 달랐던것입니다! observer 패턴을 잘 모르지만 공부해서 반영해보도록 하겠습니다!

}
}

const app = new App();
37 changes: 37 additions & 0 deletions src/component/ToDoInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export class ToDoInput {
state;
$target;
props;
constructor(target,props){
this.$target = target;
this.props = props;
this.state = {
toDoItem : ""
}
this.initEventListener();
}

render () {

}

initEventListener () {
this.$target.addEventListener('input',({target})=>{
this.setState({toDoItem: target.value})
})
this.$target.addEventListener('keydown',({key})=>{
if(key === "Enter") {
this.props.addToDoItem(this.state.toDoItem);
this.reset();
};
})
}

setState (payload) {
this.state={...this.state,...payload}
}
reset(){
this.setState({toDoItem:""});
this.$target.value = "";
}
}
74 changes: 74 additions & 0 deletions src/component/ToDoList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { TODO_STATE } from "../constant/index.js";
const getStateClass = (state) => {
return state === TODO_STATE.COMPLETED ? 'class="completed"' :
state === TODO_STATE.EDITING ? 'class="editing"' :
'';
}
export class ToDoList {
state;
$target;
constructor(target){
this.$target = target;
this.setState({

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

state를 초기화하는 방식이 TodoInput과 다릅니다.

items:[]
})
}
render(){
const {items} = this.state;
this.$target.innerHTML = items.map(({state,title})=>`
<li ${ getStateClass(state) }>
<div class="view">
<input class="toggle" type="checkbox" ${state === TODO_STATE.COMPLETED ? 'checked' : '' }/>
<label class="label">${title}</label>
<button class="destroy"></button>
</div>
${ state === TODO_STATE.EDITING ? `<input class="edit" value="${title}" />` : '' }
</li>
`).join('')

}
initEventListener(){
this.addToggleEvent();
this.removeToggleEvent();

}

addToggleEvent(){
const toggleComponents = this.$target.querySelectorAll('.toggle');
const {items} = this.state;
toggleComponents.forEach((element,idx) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

모든 토글에 리스너를 등록하는 방법 대신 이벤트위임을 통해 부모 노드에만 이벤트를 등록하는 방법을 고려해보세요.
[(https://ko.javascript.info/event-delegation)]

element.addEventListener('change',(({target})=>{
const todoItem = items[idx];
todoItem.state = target.checked ? TODO_STATE.COMPLETED : TODO_STATE.TODO
items[idx] = {...todoItem};
this.setState({items:[...items]});
})
)});
}

removeToggleEvent(){
const destroyComponents = this.$target.querySelectorAll('.destroy');
const {items} = this.state;
destroyComponents.forEach((element,idx)=>{
element.addEventListener('click',()=>{
items.splice(idx,1);
this.setState({items:[...items]})
})
})
}

setState(payload){
this.state = {...this.state, ...payload};
this.render();
this.initEventListener();
}
addItem(itemTitle){
this.setState({
items: [...this.state.items,
{
title:itemTitle, state: TODO_STATE.TODO
}]
})
}
}

2 changes: 2 additions & 0 deletions src/component/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export {ToDoList} from "./ToDoList.js"
export {ToDoInput} from "./ToDoInput.js"
5 changes: 5 additions & 0 deletions src/constant/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const TODO_STATE = {
TODO: 0,
COMPLETED: 1,
EDITING: 2,
}
Empty file added src/service/index.js
Empty file.
Empty file added src/storage/index.js
Empty file.