* 테이블 설계
CREATE TABLE History (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
log VARCHAR(255) NOT NULL,
date_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES User(id)
);
CREATE TABLE `todo`.`Card` (
`id` INT NOT NULL AUTO_INCREMENT,
`title` VARCHAR(45) NULL,
`content` VARCHAR(45) NULL,
`device` VARCHAR(45) NULL,
PRIMARY KEY (`id`),
CONSTRAINT `user_id`
FOREIGN KEY (`id`)
REFERENCES `todo`.`User` (`id`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin;
-> 수정 : card에서 date_time 도 가지는게 정렬에 좋을듯?
* http form put undefiend 해결
- 문제 : form method를 put으로 했더니, undefiend가 뜸
- 원인 : http form은 get, post만 지원함
- 해결 1 : 미들웨어 이용
네, 이 폼을 처리하기 위한 라우터를 만들어 드리겠습니다. 먼저, HTML 폼에서 몇 가지 수정이 필요합니다:
- HTML 폼의 method를 "PUT"에서 "POST"로 변경해야 합니다. HTML 폼은 기본적으로 GET과 POST만 지원하기 때문입니다.
- 폼 action URL에 taskId를 포함시켜야 합니다.
수정된 HTML 폼:
<div id="edit-doing" style="display: none;">
<form action="/card/<%= task.id %>" method="POST">
<input type="hidden" name="_method" value="PUT">
<input type="text" id="title" name="title" required value="<%= task.title %>"><br><br>
<input type="text" id="details" name="details" required value="<%= task.details %>"><br><br>
<button type="button" id="cancel-btn2">취소</button>
<button type="submit" id="save-btn2">저장</button>
</form>
</div>
이제 이 폼을 처리하는 Express 라우터를 만들어 보겠습니다:
const express = require('express');
const router = express.Router();
const methodOverride = require('method-override');
// method-override 미들웨어 설정
router.use(methodOverride('_method'));
// PUT 요청 처리를 위한 라우터
router.put('/card/:taskId', async (req, res) => {
try {
const taskId = req.params.taskId;
const { title, details } = req.body;
// 여기에 데이터베이스 업데이트 로직을 구현합니다.
// 예를 들어:
// await Task.findByIdAndUpdate(taskId, { title, details });
// 업데이트 성공 시 리다이렉트 또는 성공 메시지 전송
res.redirect('/'); // 또는 res.json({ success: true });
} catch (error) {
console.error('Error updating task:', error);
res.status(500).json({ error: 'Failed to update task' });
}
});
module.exports = router;
이 라우터를 사용하기 위해서는 다음 단계를 따라야 합니다:
method-override
패키지 설치:npm install method-override
- 메인 app.js 또는 서버 파일에서 라우터 연결:
const express = require('express'); const app = express(); const cardRouter = require('./routes/card'); // 라우터 파일의 경로에 맞게 수정 app.use(express.urlencoded({ extended: true })); app.use(express.json()); app.use('/', cardRouter);
이 설정을 통해:
- HTML 폼에서 POST 요청을 보내지만,
_method
숨겨진 필드를 통해 서버에서 이를 PUT 요청으로 처리합니다. - 서버는
/card/:taskId
경로로 오는 PUT 요청을 처리하여 해당 task를 업데이트합니다. - 업데이트 성공 시 홈페이지로 리다이렉트하거나 성공 메시지를 전송합니다.
- 오류 발생 시 500 상태 코드와 함께 오류 메시지를 반환합니다.
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
card 컴포넌트화
- 컴포넌트마다 달라져야되는 값은 매개변수로 넘기면 된다! {a : 1}
- 컴포넌트.ejs에서는 받아온 매개변수를 사용하면된다 <%= a %>
//card component <form action="/card" method="POST"> <label for="title">제목을 입력하세요:</label><br> <input type="text" id="title" name="title" required><br><br> <label for="details">내용을 입력하세요:</label><br> <textarea id="details" name="details" required></textarea><br><br> <input type="hidden" name="status" value="<%= status %>"> <input type="hidden" name="device" value="web"> <input type="hidden" name="author" value="ralo"> <button type="button" id="<%= cancelBtnId %>">취소</button> <button type="submit">등록</button> </form>
//전 <form action="/add" method="POST"> <label for="title">제목을 입력하세요:</label><br> <input type="text" id="title" name="title" required><br><br> <label for="details">내용을 입력하세요:</label><br> <textarea id="details" name="details" required></textarea><br><br> <input type="hidden" name="status" value="todo"> <button type="button" id="cancel-btn1">취소</button> <button type="submit">등록</button> </form>
//main.ejs에서 사용예
<%- include('partials/card-input', { status: 'in-progress', cancelBtnId: 'cancel-btn1' }); %>
### card 수정 구현
- 문제 : update시, 내용이 고정되는 버그
- 원인 : 아래와같이 id로 새로운 값을 받아오고있었는데, id가 유니크 하지않아서, value가 고정되었음.
```javascript
//update.js
const editForm = document.getElementById('edit-form');
console.log(editForm);
const updatedTitle = editForm.elements['title'].value;
const updatedDetail = editForm.elements['details'].value;
- 해결 : 편집 form에 유일한값인 id를 부여 (db id 값과 동일하게) && 그 id로 find
<!--hidden edit mode--> <div id="edit-doing" style="display: none"> <form id=<%= task.id %> action="/cardUpdate" method="POST"> ... </form> </div>
const editForm = document.getElementById(taskId);
const updatedTitle = editForm.elements['title'].value;
const updatedDetail = editForm.elements['details'].value;
![image](https://github.com/user-attachments/assets/61f1d085-c45f-4c82-b4e0-a862dfbb8deb)
![image](https://github.com/user-attachments/assets/d89ce4e8-cdd1-462e-a19d-1c995430fbf6)
![image](https://github.com/user-attachments/assets/5e0c9912-6906-4758-8247-91ff1f96885f)
<br>db에도 반영됨
- 문제 2 : http form에서는 get, post 만 지원하는 문제
- 해결방법1 : HTML 폼에서 POST 요청을 보내지만, _method 숨겨진 필드를 통해 서버에서 이를 PUT 요청으로 처리
- 해결방법2 : form에서 post요청을 보내는대신, 저장버튼을 클릭하면 js에서 patch를 보내도록 구현
- 선택 : 방법2, 이유 : 더 간단해 보였고, delete.js의 로직을 재활용하면 쉽게 구현될것이라고 판단.
fetch('/card', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ id: taskId, title: updatedTitle, details: updatedDetail })
})
### this 바인딩 문제 해결
- 문제 : Drag후 상태변경을 구현하던중 아래와 같은 오류가 떳다.
![image](https://github.com/user-attachments/assets/32686a01-3fd7-4047-922f-28dc2d77b1d5)
- 원인 : 아래와같이 updateStatus 함수가 일반 함수로 정의되있었다.
![image](https://github.com/user-attachments/assets/796b5bee-b66e-407a-ae85-6a80a64108d2)
- 해결1 : arrow func
```javascript
updateStatus = async (req, res) => {
try {
const { id, status } = req.body;
// console.log(id, status);
const task = await this.appService.updateStatus(id, status);
// console.log('enmd');
if (task) {
res.json(task);
} else {
res.status(404).json({ error: 'Task not found' });
}
} catch (error) {
res.status(400).json({ error: error.message });
}
}
- other solution
- 결론 및 의문점 :
- controller에서 arrow func를 사용해야할것같다.
- service에서는 arrow func를 사용안했는데, error 가 없다 why?
드래그 과정 학습
- 초기 설정:
먼저, index.ejs에는 각각의 todo, inprogress, completedList가 있어요. 그 안에는 card들이 들어있습니다. <!-- 리스트--> <div class="inProgressCard"> <ul id="in-progress-list" class="sortable-list"> <% inProgressTasks.forEach(function(task) { %> <%- include('partials/card', { task: task }); %> <% }); %> </ul> </div>
DOMContentLoaded 이벤트 리스너를 설정하여 DOM이 완전히 로드된 후 코드가 실행되도록 합니다.
todo, in-progress, completed 목록의 DOM 요소를 가져옵니다.
- Sortable 초기화:
각 목록(todo, in-progress, completed)에 Sortable 객체를 생성합니다.
이를 통해 목록 내에서, 그리고 목록 간에 항목을 드래그할 수 있게 됩니다.
- 드래그 앤 드롭 처리:
사용자가 항목을 드래그하여 다른 목록에 놓으면 onEnd 콜백 함수가 실행됩니다.
이 함수는 항목이 놓인 새로운 목록을 확인하고 해당하는 새 상태를 결정합니다.
onEnd: function(evt) { //콜백함수, 다른영역에 놓으면 실행됨!
let newStatus = '';
if (evt.to === todoList) {
newStatus = 'todo';
} else if (evt.to === inProgressList) {
newStatus = 'in-progress';
} else if (evt.to === completedList) {
newStatus = 'completed';
}
updateTaskStatus(evt.item, newStatus); //여기서 item은 card가 되겠군.
// console.log(newStatus);
},
- 상태 업데이트:
updateTaskStatus 함수가 호출되어 서버에 새로운 상태를 알립니다.
이 함수는 fetch를 사용하여 서버에 PATCH 요청을 보냅니다.
- 서버 응답 처리:
서버 응답을 받으면 콘솔에 로그를 출력하고 페이지를 새로고침합니다.
+------------------+ +------------------+ +------------------+
| To Do | | In Progress | | Completed |
| | | | | |
| +------------+ | | +------------+ | | +------------+ |
| | Card 1 | | | | Card 2 | | | | Card 3 | |
| +------------+ | | +------------+ | | +------------+ |
| | | | | |
| +------------+ | | +------------+ | | +------------+ |
| | Card 4 | | | | Card 5 | | | | Card 6 | |
| +------------+ | | +------------+ | | +------------+ |
| | | | | |
+------------------+ +------------------+ +------------------+
^ ^ ^
| | |
| Drag & Drop | Drag & Drop |
|<---------------------->|<---------------------->|
| | |
| | |
| | |
+------------------------|------------------------+
|
v
+-------------------------------+
| updateTaskStatus |
| (PATCH request to server) |
+-------------------------------+
|
v
+-------------------------------+
| Server Updates DB |
+-------------------------------+
|
v
+-------------------------------+
| Page Reloads |
+-------------------------------+
'개발일지' 카테고리의 다른 글
24. 11. 19. 개발일지 // test-code 의존성 수정, redis 구독 리팩토링, 진행중게임에 들어올수없음 (0) | 2024.11.20 |
---|---|
24. 11. 18. 개발일지 // api vs 서비스주입, redis 캐시 (1) | 2024.11.19 |
24. 11. 17. 개발일지 redis 탐색 (0) | 2024.11.18 |
24.11.14. 발표자료 // n+1문제해결, 변경감지, redis 설계 (0) | 2024.11.14 |
24.11.14. 개발일지 // 자동배포, 깃헙액션에서 db test, ssh 터널링 db 연결 (1) | 2024.11.14 |