Skip to content

Commit bb0a963

Browse files
authored
Merge pull request #49 from Konkuk-KUIT/jiyeKa
[3주차] updateTodo 미션
2 parents dd58a09 + 3f9b9ef commit bb0a963

File tree

4 files changed

+234
-0
lines changed

4 files changed

+234
-0
lines changed

week3/jiyeKa/todo/app.js

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
const todoListEl = document.getElementById("todoList");
2+
const todoInputEl = document.getElementById("todoInput");
3+
4+
const API_URL = "http://localhost:8080/todos";
5+
6+
fetch(API_URL)
7+
.then((response) => response.json())
8+
.then((data) => renderTodo(data));
9+
10+
let currentUpdateId = null;
11+
document.getElementById("todoInput").focus();
12+
13+
const updateTodo = (todoId, originalTitle) => {
14+
15+
// 이미 수정중인 항목이 있으면 다른 항목 ✏️ 클릭 불가능
16+
if(currentUpdateId!=null && currentUpdateId!=todoId) return;
17+
18+
// 현재 수정중인 항목의 아이디 기록
19+
currentUpdateId=todoId;
20+
const todoItem = document.querySelector(`#todo-${todoId}`);
21+
22+
// 기존 내용 삭제 후 input & SaveBtn 생성
23+
todoItem.innerHTML = "";
24+
25+
const inputEl = document.createElement("input");
26+
inputEl.id="inputEl";
27+
inputEl.type = "text";
28+
inputEl.value = originalTitle;
29+
const saveBtn = document.createElement("button");
30+
saveBtn.textContent = "Save";
31+
32+
// Button 스타일 변경
33+
saveBtn.style.cssText =
34+
"background-color: white; color: black; font-size: 0.7em; padding: 5px;";
35+
36+
todoItem.appendChild(inputEl);
37+
todoItem.appendChild(saveBtn);
38+
39+
// ✏️클릭 시 커서 위치 자동 포커스
40+
document.getElementById("inputEl").focus();
41+
42+
// saveBtn 클릭 시 title 업데이트
43+
saveBtn.onclick = () => {
44+
const updatedTitle = inputEl.value;
45+
46+
fetch(API_URL + "/" + todoId, {
47+
method: "PATCH",
48+
headers: {
49+
"Content-Type": "application/json",
50+
},
51+
body: JSON.stringify({ title: updatedTitle }),
52+
})
53+
.then(() => {
54+
return fetch(API_URL);
55+
})
56+
.then((response) => response.json())
57+
.then((data) => {
58+
renderTodo(data);
59+
currentUpdateId=null;
60+
});
61+
};
62+
63+
// 엔터키 입력시 수정 Save 가능
64+
document.getElementById("inputEl").addEventListener('keydown',function(event){
65+
if(event.key === 'Enter'){
66+
saveBtn.onclick();
67+
}
68+
});
69+
70+
};
71+
72+
const renderTodo = (newTodos) => {
73+
todoListEl.innerHTML = "";
74+
newTodos.forEach((todo) => {
75+
const listEl = document.createElement("li");
76+
listEl.textContent = todo.title;
77+
listEl.id = `todo-${todo.id}`;
78+
79+
const deleteEl = document.createElement("span");
80+
deleteEl.textContent = "🗑️";
81+
deleteEl.onclick = () => deleteTodo(todo.id);
82+
83+
const updateEl = document.createElement("span");
84+
updateEl.textContent = "✏️";
85+
updateEl.onclick = () => updateTodo(todo.id, todo.title);
86+
87+
listEl.append(deleteEl);
88+
listEl.append(updateEl);
89+
todoListEl.append(listEl);
90+
});
91+
};
92+
93+
94+
// 엔터키 입력 시 add 가능하도록
95+
document.getElementById("todoInput").addEventListener('keydown',function(event){
96+
if(event.key == "Enter"){
97+
addTodo();
98+
}
99+
});
100+
101+
102+
const addTodo = () => {
103+
const title = todoInputEl.value;
104+
const date = new Date();
105+
const createdAt = date.toDateString();
106+
107+
if (!title) return;
108+
109+
const newTodo = {
110+
id: date.getTime().toString(),
111+
title,
112+
createdAt,
113+
};
114+
115+
fetch(API_URL, {
116+
method: "POST",
117+
headers: {
118+
"Content-Type": "application/json",
119+
},
120+
body: JSON.stringify({ ...newTodo, completed: false }),
121+
})
122+
.then((response) => response.json())
123+
.then(() => {
124+
todoInputEl.value = "";
125+
return fetch(API_URL);
126+
})
127+
.then((response) => response.json())
128+
.then((data) => renderTodo(data));
129+
};
130+
131+
const deleteTodo = (todoId) => {
132+
fetch(API_URL + "/" + todoId, {
133+
method: "DELETE",
134+
})
135+
.then(() => fetch(API_URL))
136+
.then((response) => response.json())
137+
.then((data) => renderTodo(data));
138+
};

week3/jiyeKa/todo/db.json

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"todos": [
3+
{
4+
"id": "1727956553018",
5+
"title": "하이하이",
6+
"createdAt": "Thu Oct 03 2024",
7+
"completed": false
8+
},
9+
{
10+
"id": "1727956560017",
11+
"title": "",
12+
"createdAt": "Thu Oct 03 2024",
13+
"completed": false
14+
}
15+
]
16+
}

week3/jiyeKa/todo/index.css

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
* {
2+
box-sizing: border-box;
3+
margin: 0;
4+
padding: 0;
5+
}
6+
body {
7+
background-color: #f5f5f5;
8+
font-family: "Arial", sans-serif;
9+
}
10+
.app {
11+
width: 400px;
12+
margin: 30px auto;
13+
background-color: #fff;
14+
padding: 20px;
15+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
16+
}
17+
.header {
18+
font-size: 1.5em;
19+
margin-bottom: 20px;
20+
text-align: center;
21+
}
22+
.inputContainer {
23+
display: flex;
24+
}
25+
#todoInput {
26+
flex: 1;
27+
padding: 10px;
28+
font-size: 1em;
29+
border: 1px solid #ddd;
30+
}
31+
button {
32+
background-color: #28a745;
33+
color: #fff;
34+
padding: 10px;
35+
font-size: 1em;
36+
cursor: pointer;
37+
}
38+
button:hover {
39+
background-color: #218838;
40+
}
41+
ul {
42+
list-style-type: none;
43+
}
44+
li {
45+
padding: 10px;
46+
border-bottom: 1px solid #ddd;
47+
display: flex;
48+
justify-content: space-between;
49+
align-items: center;
50+
}
51+
li:last-child {
52+
border-bottom: none;
53+
}
54+
.deleteBtn {
55+
cursor: pointer;
56+
color: #ff0000;
57+
}
58+
.deleteBtn:hover {
59+
text-decoration: underline;
60+
}
61+

week3/jiyeKa/todo/index.html

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>Todo App</title>
6+
<link rel="stylesheet" href="index.css" />
7+
</head>
8+
<body>
9+
<div class="app">
10+
<div class="header">My Todos</div>
11+
<div class="inputContainer">
12+
<input id="todoInput" placeholder="What needs to be done?" />
13+
<button onclick="addTodo()">Add</button>
14+
</div>
15+
<ul id="todoList"></ul>
16+
</div>
17+
<script src="app.js"></script>
18+
</body>
19+
</html>

0 commit comments

Comments
 (0)