Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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: 4 additions & 2 deletions detail.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="./func_detail.js"></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Detail TODO List</title>
Expand All @@ -9,10 +10,11 @@
<section id="container">
<h1 class="title">TODO LIST</h1>
<div class="input-container">
<input type="text" class="todo-input" />
<!-- onkeyup="(event) => enterKey(event)"로 명시해도 괜찮음 -->
<input type="text" class="todo-input" onkeyup="enterKey(event)"/>
</div>
<div class="filter-container">
<select id="todo-filter">
<select id="todo-filter" onchange="listFilter(event)">
<option value="all">전체</option>
<option value="todo">할일</option>
<option value="done">완료</option>
Expand Down
151 changes: 151 additions & 0 deletions func_detail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
function enterKey(event) {
if(event.key === 'Enter') {
createTodo();
}
}

function createTodo() {
const list = document.getElementById('todo-list');
const input = document.querySelector('.todo-input');
const inputText = input.value.trim();

if (inputText === '') {
alert("내용을 입력하세요.");
return;
}

const isConfirm = confirm(`"${inputText}"를 저장하시겠습니까?`);
if (!isConfirm) {
return;
}

// 피드백) Element Create하는 부분들 모듈화(함수를 모듈화해서 객체로 전달하는 것이 좋다. 버튼을 생성할때, 생성 함수는 1개에 인자를 다르게 해서 생성하는 느낌)

// Create List Element
const newTodo = document.createElement('li');

// Checkbox
const checkbox = createCheckbox('input', 'checkbox', 'todo-checkbox')
newTodo.appendChild(checkbox);

// TextContent
const todoText = document.createElement('span');
todoText.classList.add('todo-text');
todoText.textContent = inputText;
newTodo.appendChild(todoText);

// Button
const editButton = createButton('button', 'Edit', 'edit-btn');
newTodo.appendChild(editButton);
const saveButton = createButton('button', 'Save', 'save-btn');
newTodo.appendChild(saveButton);
const deleteButton = createButton('button', 'X', 'delete-btn');
newTodo.appendChild(deleteButton);

// // 피드백) eventListener는 이벤트를 통해서 조작해야하기 때문에 editTodo ParentNode정돈 허용해야한다.
// // -> eventListener는 이벤트가 발생한 요소에 대한 파라미터를 제공함.
list.appendChild(newTodo);

input.value = '';
}

function createCheckbox(tag, type, className) {
const checkbox = document.createElement(tag);
checkbox.type = type;
checkbox.classList.add(className);

return checkbox;
}

function createButton(tag, buttonText, className) {
const button = document.createElement(tag);
button.textContent = buttonText;
button.classList.add(className);
button.addEventListener('click', (e) => { handleButtonEvent(e) } );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

이 또한 파라미터로 받으면됩니다 :) 아래 handleButtonEvent 에서 분기타는게 이뻐보일수도 있긴한데
차라리 이런 형태로 갈거라면 createButton 의 파라미터를 객체로 변경한 뒤
각 버튼타입의 객체를 Enum 처럼 const 로 정의해놓아
createButton 에 특정 타입의 객체 파라미터를 주면 그 객체 내 요소들 가져다가 타입 버튼을 만드는게 좋을듯해요.


if (buttonText === 'Save') button.style.display = 'none';

return button;
}

function handleButtonEvent(e) {
const buttonName = e.target.className;
switch (buttonName) {
case 'edit-btn' :
editTodo(e);
break;
case 'save-btn' :
saveTodo(e);
break;
case 'delete-btn' :
deleteTodo(e);
break;
default :
console.warn('Unknown Button Action');
break;
}
}

function listFilter(event) {
const filter = event.target.value;
const todoList = document.querySelectorAll('#todo-list li');

todoList.forEach(todo => {
const checkbox = todo.querySelector('.todo-checkbox');
const isChecked = checkbox.checked;

if (filter === "all") {
console.log(filter);
todo.style.display = 'list-item';
} else if (filter === 'todo' && !isChecked) {
todo.style.display = 'list-item';
} else if (filter === 'done' && isChecked) {
todo.style.display = 'list-item';
} else {
todo.style.display = 'none';
}
})
}

function editTodo(event) {
// 피드백) 하나의 컴포넌트가 두 개 이상의 작업을 수행하게 되어있음.
// 역할을 나눠놓는 것이 좋다. Edit, Save
const item = event.target.parentNode;
const todo = item.querySelector('.todo-text');
const editBtn = item.querySelector('.edit-btn');
const saveBtn = item.querySelector('.save-btn');
saveBtn.style.display = 'inline';
editBtn.style.display = 'none';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

editTodo 와 saveTodo 의 코드 흐름의 형상(?)을 유사하게 만들 수 있을거같습니다.
Pseudo code 를 써보면 아래와 같아요. 아 그리고 saveBtn 보다 saveButton 이 좋을듯합니다. 약어 지양으로

function editTodo(event) {
    const item = event.target.parentNode;
    const text = item.querySelector('.todo-text');

    const input = createInputFromText(text);
    item.replaceChild(input, text);

    toggleButton('EDIT_MODE'); // 내부에서 editButton, saveButton 교체
}
function saveTodo(event) {
    const item = event.target.parentNode;
    const input = item.querySelector('.todo-text');

    const text = createTextFromInput(input);
    item.replaceChild(text, input);

    toggleButton('SAVE_MODE'); // 내부에서 editButton, saveButton 교체
}

좀 변태같긴하지만 저 개인적으론 코드의 형상을 맞추는걸 선호하는 편입니다.
다른 사람이 코드보았을때 명확히 이해가능하거든요. 물론 개발 시간이 넉넉하다는 전제하에


const input = document.createElement('input');
// Map으로 중앙화도 가능
input.setAttribute('type', 'text');
input.setAttribute('class', 'todo-text');
input.setAttribute('value', todo.textContent);
item.replaceChild(input, todo);
}

function saveTodo(event) {
const item = event.target.parentNode;
const editBtn = item.querySelector('.edit-btn');
const saveBtn = item.querySelector('.save-btn');

const input = item.querySelector('.todo-text');
if (input.value.trim() === '') {
alert('내용을 입력하세요.');
return;
}
const saveTodo = document.createElement('span');
saveTodo.classList.add('todo-text');
saveTodo.textContent = input.value.trim();

item.replaceChild(saveTodo, input);
editBtn.style.display = 'inline';
saveBtn.style.display = 'none';
}

// 주어진 걸 최대한 쓰자 이벤트리스너의 파라미터.
function deleteTodo(event) {
const todo = event.target.parentNode;
todo.remove();
}
25 changes: 25 additions & 0 deletions func_simple.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
document.addEventListener('DOMContentLoaded', function () {
const input = document.querySelector('.todo-input');
const saveButton = document.querySelector('.input-container input[type="button"]');
const list = document.getElementById('todo-list');

saveButton.addEventListener('click', function () {
const inputText = input.value.trim();
if (inputText === '') {
alert("내용을 입력하세요.");
return;
}

const isConfirm = confirm(`"${inputText}"를 저장하시겠습니까?`);
if (!isConfirm) {
return;
}

const newTodo = document.createElement('li');
newTodo.textContent = inputText;

list.appendChild(newTodo);

input.value = '';
});
});
1 change: 1 addition & 0 deletions simple.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="./func_simple.js"></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Simple TODO List</title>
Expand Down