Flask practice blog 구축 인터페이스(UI) posts.html (3/3)

2025. 4. 22. 18:26·과제

📌 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
'과제' 카테고리의 다른 글
  • 📚 Django 프로젝트 시작하기 - 가상환경 구축부터 서버 실행까지
  • Flask practice blog 구축 API 라우트 설정 posts_routes.py (2/3)
  • Flask practice blog 구축 app.py, db.yaml (1/3)
  • Flask와 Smorest api를 이용한 책 데이터를 관리하는 기능 구현(Flask 2일차)
Chansman
Chansman
안녕하세요! 코딩을 시작한 지 얼마 되지 않은 초보 개발자 찬스맨입니다. 이 블로그는 제 학습 기록을 남기고, 다양한 코딩 실습을 통해 성장하는 과정을 공유하려고 합니다. 초보자의 눈높이에 맞춘 실습과 팁, 그리고 개발하면서 겪은 어려움과 해결 과정을 솔직하게 풀어내려 합니다. 함께 성장하는 개발자 커뮤니티가 되기를 바랍니다.
  • Chansman
    찬스맨의 프로그래밍 스토리
    Chansman
  • 전체
    오늘
    어제
    • 분류 전체보기 (472) N
      • Python (31)
      • 프로젝트 (43)
      • 과제 (21)
      • Database (40)
      • 멘토링 (7)
      • 특강 (18)
      • 기술블로그 (126) N
      • AI 분석 (4)
      • HTML & CSS (31)
      • JavaScript (17)
      • AWS_Cloud (21)
      • 웹스크래핑과 데이터 수집 (14)
      • Flask (42)
      • Django (34)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Chansman
Flask practice blog 구축 인터페이스(UI) posts.html (3/3)
상단으로

티스토리툴바