📌 posts.html - 블로그 게시글 관리 페이지
posts.html는 사용자 인터페이스(UI)를 담당하는 HTML 페이지입니다. 이 페이지는 사용자가 게시글을 생성, 수정, 삭제할 수 있는 폼과 게시글 목록을 표시합니다. JavaScript와 Axios를 사용하여 백엔드 API와 상호작용하고 데이터를 동적으로 처리합니다.
1. HTML 구조
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Blog Posts</title>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<h1>Blog Posts</h1>
<h2>Create a New Post</h2>
<form id="postForm">
<input type="hidden" id="postId" value="" />
Title: <input type="text" id="title" /><br />
Content:<br />
<textarea id="content"></textarea><br />
<input type="submit" value="Create Post" id="createButton" />
<input type="button" value="Update Post" id="updateButton" onclick="submitUpdateForm()" style="display: none" />
</form>
<hr />
<h2>All Posts</h2>
<ul id="postsList"></ul>
<script>
// JavaScript 코드
</script>
</body>
</html>
- <head> 섹션: 페이지의 제목을 "Blog Posts"로 설정하고, axios 라이브러리를 로드하여 HTTP 요청을 처리합니다.
- <body> 섹션: 게시글을 생성하거나 수정할 수 있는 폼과 게시글 목록을 표시하는 ul 요소가 포함됩니다.
2. 게시글 생성 및 수정 폼
<form id="postForm">
<input type="hidden" id="postId" value="" />
Title: <input type="text" id="title" /><br />
Content:<br />
<textarea id="content"></textarea><br />
<input type="submit" value="Create Post" id="createButton" />
<input type="button" value="Update Post" id="updateButton" onclick="submitUpdateForm()" style="display: none" />
</form>
- postForm: 사용자가 게시글을 작성하거나 수정할 때 사용하는 폼입니다.
- **title**과 content 필드는 게시글의 제목과 내용을 입력받습니다.
- createButton: 새 게시글을 생성하는 버튼입니다.
- updateButton: 게시글을 수정할 때 사용되는 버튼입니다. 수정 시에는 createButton을 숨기고 updateButton을 표시합니다.
3. 게시글 목록 출력
<h2>All Posts</h2>
<ul id="postsList"></ul>
- postsList: 백엔드에서 가져온 게시글 목록을 표시할 ul 요소입니다. 각 게시글은 li 요소로 생성되어 표시됩니다.
🚦 동작 원리 및 코드 흐름
1. 게시글 생성 및 수정
document.getElementById("postForm").addEventListener("submit", function (e) {
e.preventDefault();
const title = document.getElementById("title").value;
const content = document.getElementById("content").value;
if (currentEditingId === null) {
createNewPost(title, content);
} else {
updatePost(currentEditingId, title, content);
}
});
- submit 이벤트 처리: 사용자가 폼을 제출하면, 현재 작성 중인 게시글이 수정 중인지 확인하고, 새 게시글을 작성할지 수정할지 결정합니다.
- currentEditingId가 null이면 새 게시글을 생성하고, 그렇지 않으면 기존 게시글을 수정합니다.
2. 새 게시글 생성
function createNewPost(title, content) {
axios
.post("/posts", { title, content })
.then(function (response) {
loadPosts();
resetForm();
})
.catch(function (error) {
console.error(error);
});
}
- createNewPost(): POST /posts API를 호출하여 새 게시글을 생성합니다.
- 성공하면 loadPosts() 함수로 게시글 목록을 다시 로드하고, resetForm() 함수로 폼을 초기화합니다.
3. 게시글 수정
function updatePost(id, title, content) {
axios
.put("/posts/" + id, { title, content })
.then(function (response) {
loadPosts();
resetForm();
})
.catch(function (error) {
console.error(error);
});
}
- updatePost(): PUT /posts/{id} API를 호출하여 특정 게시글을 수정합니다.
- 성공하면 게시글 목록을 갱신하고 폼을 초기화합니다.
4. 게시글 목록 로드
function loadPosts() {
axios
.get("/posts")
.then(function (response) {
const posts = response.data;
const postsList = document.getElementById("postsList");
postsList.innerHTML = "";
posts.reverse().forEach((post) => {
const listItem = document.createElement("li");
listItem.innerHTML = `
<h3>ID: ${post.id}</h3>
<h3>TITLE: ${post.title}</h3>
<p>CONTENT: ${post.content}</p>
<button onclick="deletePost(${post.id})">Delete</button>
<button onclick="loadPostForEditing(${post.id})">Edit</button>
`;
postsList.appendChild(listItem);
});
})
.catch(function (error) {
console.error(error);
});
}
- loadPosts(): /posts API를 호출하여 모든 게시글을 가져오고, 이를 HTML 목록으로 출력합니다.
- 게시글 목록을 reverse() 메서드를 사용하여 최신 글이 위로 오도록 정렬합니다.
- 각 게시글에는 삭제 및 수정 버튼이 있습니다.
5. 게시글 수정 로드
function loadPostForEditing(id) {
axios
.get("/posts/" + id)
.then(function (response) {
const post = response.data;
currentEditingId = post.id;
document.getElementById("title").value = post.title;
document.getElementById("content").value = post.content;
document.getElementById("createButton").style.display = "none";
document.getElementById("updateButton").style.display = "inline";
})
.catch(function (error) {
console.error(error);
});
}
- loadPostForEditing(): GET /posts/{id} API를 호출하여 특정 게시글의 데이터를 가져오고, 이를 폼에 채웁니다.
- 수정할 게시글을 선택하면, 수정 버튼이 표시되고 생성 버튼은 숨겨집니다.
6. 게시글 삭제
function deletePost(id) {
if (confirm("Are you sure you want to delete this post?")) {
axios
.delete("/posts/" + id)
.then(function (response) {
loadPosts();
})
.catch(function (error) {
console.error(error);
});
}
}
- deletePost(): DELETE /posts/{id} API를 호출하여 특정 게시글을 삭제합니다.
- 삭제 확인을 위한 confirm() 다이얼로그를 표시하고, 삭제 후 게시글 목록을 갱신합니다.
7. 폼 초기화
function resetForm() {
currentEditingId = null;
document.getElementById("title").value = "";
document.getElementById("content").value = "";
document.getElementById("createButton").style.display = "inline";
document.getElementById("updateButton").style.display = "none";
}
- resetForm(): 폼을 초기화하여 새 게시글을 작성할 수 있도록 합니다. 수정 작업 후에도 사용됩니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Blog Posts</title>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<h1>Blog Posts</h1>
<h2>Create a New Post</h2>
<form id="postForm">
<input type="hidden" id="postId" value="" />
Title: <input type="text" id="title" /><br />
Content:<br />
<textarea id="content"></textarea><br />
<input type="submit" value="Create Post" id="createButton" />
<input type="button" value="Update Post" id="updateButton" onclick="submitUpdateForm()" style="display: none" />
</form>
<hr />
<h2>All Posts</h2>
<ul id="postsList"></ul>
<script>
let currentEditingId = null;
document
.getElementById("postForm")
.addEventListener("submit", function (e) {
e.preventDefault();
const title = document.getElementById("title").value;
const content = document.getElementById("content").value;
if (currentEditingId === null) {
createNewPost(title, content);
} else {
updatePost(currentEditingId, title, content);
}
});
function createNewPost(title, content) {
axios
.post("/posts", { title, content })
.then(function (response) {
console.log(response);
loadPosts();
resetForm();
})
.catch(function (error) {
console.error(error);
});
}
function updatePost(id, title, content) {
axios
.put("/posts/" + id, { title, content })
.then(function (response) {
console.log(response);
loadPosts();
resetForm();
})
.catch(function (error) {
console.error(error);
});
}
function loadPosts() {
axios
.get("/posts")
.then(function (response) {
const posts = response.data;
const postsList = document.getElementById("postsList");
postsList.innerHTML = "";
posts.reverse().forEach((post) => {
const listItem = document.createElement("li");
listItem.innerHTML = `
<h3>ID: ${post.id}</h3>
<h3>TITLE: ${post.title}</h3>
<p>CONTENT: ${post.content}</p>
<button onclick="deletePost(${post.id})">Delete</button>
<button onclick="loadPostForEditing(${post.id})">Edit</button>
`;
postsList.appendChild(listItem);
});
})
.catch(function (error) {
console.error(error);
});
}
function loadPostForEditing(id) {
axios
.get("/posts/" + id)
.then(function (response) {
const post = response.data;
console.log("post", post);
currentEditingId = post.id;
document.getElementById("title").value = post.title;
document.getElementById("content").value = post.content;
document.getElementById("createButton").style.display = "none";
document.getElementById("updateButton").style.display = "inline";
})
.catch(function (error) {
console.error(error);
});
}
function resetForm() {
currentEditingId = null;
document.getElementById("title").value = "";
document.getElementById("content").value = "";
document.getElementById("createButton").style.display = "inline";
document.getElementById("updateButton").style.display = "none";
}
function submitUpdateForm() {
const title = document.getElementById("title").value;
const content = document.getElementById("content").value;
console.log("currentEditingId", currentEditingId);
if (currentEditingId) {
updatePost(currentEditingId, title, content);
} else {
console.error("No post is currently being edited.");
}
}
function deletePost(id) {
if (confirm("Are you sure you want to delete this post?")) {
axios
.delete("/posts/" + id)
.then(function (response) {
console.log(response);
loadPosts();
})
.catch(function (error) {
console.error(error);
});
}
}
loadPosts();
</script>
</body>
</html>
✅ 마무리 요약 및 복습 포인트
- CRUD 기능 구현: 이 페이지는 사용자가 게시글을 생성, 조회, 수정, 삭제할 수 있도록 완전한 CRUD 기능을 제공합니다.
- Axios: 비동기 HTTP 요청을 처리하기 위해 Axios 라이브러리를 사용합니다. 이를 통해 서버와의 실시간 상호작용을 가능하게 합니다.
- 동적 UI 업데이트: 각 API 요청 후 게시글 목록을 동적으로 갱신하며, 폼을 초기화하여 사용자가 편리하게 작업을 이어갈 수 있게 합니다.
'과제' 카테고리의 다른 글
📚 Django 프로젝트 시작하기 - 가상환경 구축부터 서버 실행까지 (0) | 2025.04.30 |
---|---|
Flask practice blog 구축 API 라우트 설정 posts_routes.py (2/3) (0) | 2025.04.22 |
Flask practice blog 구축 app.py, db.yaml (1/3) (0) | 2025.04.22 |
Flask와 Smorest api를 이용한 책 데이터를 관리하는 기능 구현(Flask 2일차) (0) | 2025.04.18 |
Flask와 Jinja 템플릿으로 사용자 목록 웹 페이지 만들어보기(Flask 1일차) (0) | 2025.04.17 |