스터디/back

17장 ~ 19장

ㅈㅣ니 2024. 1. 4.
반응형

17장 웹 페이지에서 댓글 등록하기

이번 장에서는 댓글 등록을 위한 뷰 페이지를 만들고, JS 코드로 댓글 생성 요청을 보내고 응답 받는 것을 해보겠다.

그동안은 REST API 요청을 보낼 때 POSTMAN을 사용했었는데, 실제 게시판은 해당 웹 페이지에서 바로 요청을 보낸다.

이를 위해 사용하는 자바스크립트 API는 다음과 같다.

  • document.querySelector() : 웹 페이지에서 특정 요소(버튼)를 찾아 반환
  • addEventListener() : 특정 요소에 이벤트가 발생(버튼 클릭)했을 때 특정 동작(댓글 객체 전달) 수행
  • fetch() : 웹 페이지에서 REST API 요청 (POST 요청)을 보낸다.

_new.mustache

<div class="card m-2" id="comments-new">
    <div class="card-body">
        <!-- 댓글 작성 폼 -->
        <form>
            <!-- 닉네임 입력 -->
            <div class="mb-3">
                <label class="form-label">닉네임</label>
                <input type="text" class="form-control" id="new-comment-nickname">
            </div>
            <!-- 댓글 본문 입력 -->
            <div class="mb-3">
                <label class="form-label">댓글 내용</label>
                <textarea type="text" class="form-control" rows="3" id="new-comment-body"></textarea>
            </div>
            <!-- 히든 인풋 -->
            {{#article}}
                <input type="hidden" id="new-comment-article-id" value="{{id}}">
            {{/article}}
            <!-- 전송 버튼 -->
            <button type="submit" class="btn btn-primary" id="comment-create-btn">댓글 작성</button>
        </form>

    </div>
</div>

 

여기서 히든 인풋이란. 

웹 페이지에 표시되지 않는 요소로, 보이지는 않지만 값을 가지고 있어야 할 때 사용한다.

이제 [댓글 작성] 버튼을 클릭했을 때 댓글을 입력할 수 있게 만들겠다.

이 부분은 자바스크립트로 구현한다...

 

자바스크립트로 댓글 달기

앞서 작성한 _new.mustache 밑에 <script> 태그를 추가한다.

querySelector는 웹페이지에서 특정 요소를 선택할 때 사용한다.

여기서는 특정 id 값을 이용하여 특정 요소를 찾았는데, id 값 앞에 #을 붙여서 찾았다.(이걸 아이디 선택자라고 한다.)

 

새 댓글 자바스크립트 객체 생성하기

<script>
    {
        // 댓글 생성 버튼 변수화
        const commentCreateBtn = document.querySelector("#comment-create-btn");
        // 댓글 클릭 이벤트 감지
        commentCreateBtn.addEventListener("click", function(){
            // 새 댓글 객체 생성
            const comment = {
                // 새 댓글의 닉네임
                nickname: document.querySelector("#new-comment-nickname").value,
                // 새 댓글의 본문
                body: document.querySelector("#new-comment-body").value,
                // 부모 게시글의 id
                articleId: document.querySelector(" #new-comment-article-id").value
            };
            // 댓글 객체 출력
            console.log(comment);
        });
    }
</script>

 

자바스크립트로 REST API 호출하고 응답 처리하기

 

이제는 fetch()함수를 이용하여  HTTP 통신을 해보겠다. ( GET, POST, PATCH, DELETE 같은 요청을 보내고 응답 받을 수 있다.)

// fetch() - 비동기 통신을 위한 API
const url = "/api/articles/" + comment.articleId + "/comments";
fetch(url, {
    method: "POST",
    headers: {
        "Content-Type": "application/json"
    },
    body: JSON.stringify(comment)   //comment 객체를 JSON 문자열로 변환해 전송
}).then(response => {
    // HTTP 응답 코드에 따른 메시지 출력
    const msg = (response.ok) ? "댓글이 등록됐습니다." : "댓글 등록 실패..!";
    alert(msg);
    // 현재 페이지 새로 고침
    window.location.reload();
});

[요청]

첫 번째 전달값 : API 주소

두 번재 전달값 : 요청 메서드, 헤더 정보, 전송 본문 (전송 본문은 comment 객체를 JSON 형태로 변환해 전송하기 위해 JSON.stringify() 메서드를 사용한다.)

 

1분 퀴즈 ) 다음 자바스크립트에 관한 설명 중 잘못된 것을 고르세요.

 alert()는 입력 문자열을 브라우저 콘솔에 출력한다.

 fetch()는 API 요청을 보내고 응답을 받아 처리할 수 있게 한다.

 JSON.stringify()는 객체를 입력받아 JSON 문자열로 반환한다.

 addEventListener()는 특정 요소가 이벤트를 감지해 처리하게 한다.

 document.querySelector()는 웹 페이지에서 특정 요소를 찾아 반환한다.

답 : 1 -> 메시지가 뜨게 함..

 

18장 웹 페이지에서 댓글 수정하기

댓글 수정 페이지는 모달 창으로 구현할 것이다.

 

[ _list.mustache ]

<div id="comments-list">
    {{#commentDtos}}        <!--댓글 목록 순회-->
        <div class="card m-2" id="comments-{{id}}">
            <div class="card-header">
                {{nickname}}
                <button type="button"
                        class="btn btn-sm btn-outline-primary"
                        data-bs-toggle="modal"
                        data-bs-target="#comment-edit-modal"
                        data-bs-id="{{id}}"
                        data-bs-nickname="{{nickname}}"
                        data-bs-body="{{body}}"
                        data-bs-article-id="{{articleId}}">
                    수정</button>
            </div>

            <div class="card-body">
                {{body}}
            </div>
        </div>
    {{/commentDtos}}

</div>

<!-- Modal -->
<div class="modal fade" id="comment-edit-modal" tabindex="-1" >
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title fs-5" id="exampleModalLabel">댓글 수정</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <!-- 댓글 수정 폼 -->
                <form>
                    <!-- 닉네임 입력 -->
                    <div class="mb-3">
                        <label class="form-label">닉네임</label>
                        <input type="text" class="form-control" id="edit-comment-nickname">
                    </div>
                    <!-- 댓글 본문 입력 -->
                    <div class="mb-3">
                        <label class="form-label">댓글 내용</label>
                        <textarea type="text" class="form-control" rows="3" id="edit-comment-body"></textarea>
                    </div>
                    <!-- 히든 인풋 -->
                        <input type="hidden" id="edit-comment-id">
                        <input type="hidden" id="edit-comment-article-id">
                    <!-- 전송 버튼 -->
                    <button type="submit" class="btn btn-primary" id="comment-update-btn">수정 완료</button>
                </form>
            </div>
        </div>
    </div>
</div>

 

 

 

자바스크립트로 댓글 수정하기

 

[ _list.mustache ]

html 태그 밑에 <script> 태그 부분이다.

<!-- 모달 이벤트 처리 -->
<script>
    {
        // 모달 요소 선택
        const commentEditModal = document.querySelector("#comment-edit-modal");
        // 모달 이벤트 감지
        commentEditModal.addEventListener("show.bs.modal", function (event) {
            // 1. 트리거 버튼 선택
            const triggerBtn = event.relatedTarget;
            // 2. 데이터 가져오기
            const id = triggerBtn.getAttribute("data-bs-id");       // id 가져오기
            const nickname = triggerBtn.getAttribute("data-bs-nickname");       // 닉네임 가져오기
            const body = triggerBtn.getAttribute("data-bs-body");       // 본문 가져오기
            const articleId = triggerBtn.getAttribute("data-bs-article-id");        // 부모 id 가져오기
            // 3. 수정 폼에 데이터 반영
            document.querySelector("#edit-comment-nickname").value = nickname;  // 닉네임 반영
            document.querySelector("#edit-comment-body").value = body;      // 댓글 본문 반영
            document.querySelector("#edit-comment-id").value = id;      // id 반영
            document.querySelector("#edit-comment-article-id").value = articleId;       // 부모 id 반영
        });
    }
</script>

 

기존의 댓글 데이터를 가져오고, 수정 버튼을 눌렀을 때 수정 폼에 이전 댓글 데이터가 전달될 수 있게 할 것이다.

 

[ 모달 동작 이벤트 타입 ]

show.bs.modal 모달이 표시되기 직전 실행되는 이벤트
shown.bs.modal 모달이 표시된 후 실행되는 이벤트
hide.bs.modal 모달이 숨겨지기 직전 실행되는 이벤트
hidden.bs.modal 모달이 숨겨진 후 실행되는 이벤트

 

위의 코드를 설명하자면,

show.bs.modal - 모달이 열리기 직전에 발생하는 이벤트를 의미하고,

function(event) 이벤트를 받아서 처리하는 함수로, 이벤트 핸들러라고 한다.

function(evnet) 의 event - 발생된 이벤트 정보를 가리키는 매개변수이며, 여기서는 show.bs.modal을 가리킨다.

 

 

해당 내용 반영

히든 인풋 요소의 value 값 (댓글 id :5 , 부모 id : 5 )이 잘 들어있는 지 확인했다.]

 

수정 완료 버튼 클릭 시 REST API 호출 응답

{
        // 수정 완료 버튼 선택
        const commentUpdateBtn = document.querySelector("#comment-update-btn");
        // 클릭 이벤트 처리
        commentUpdateBtn.addEventListener("click", function() {
            // 수정 댓글 객체 생성
            const comment = {       // 변수 선언
                id: document.querySelector("#edit-comment-id").value,
                nickname: document.querySelector("#edit-comment-nickname").value,
                body: document.querySelector("#edit-comment-body").value,
                article_id: document.querySelector("#edit-comment-article-id").value
            };
            console.log(comment);       // 객체 생성 확인
            // 수정 REST API 호출
            const url = "/api/comments/" + comment.id;
            fetch(url, {
                method: "PATCH",
                headers: {
                    "Content-Type": "application/json"
                },
                body: JSON.stringify(comment)       // comment 객체를 JSON 문자열로 변환 전송
            }).then(response => {
                // HTTP 응답 코드에 따른 메시지 출력
                const msg = (response.ok) ? "댓글이 수정됐습니다." : "댓글 수정 실패...!";
                alert(msg);
                // 현재 페이지 새로 고침
                window.location.reload();

            });
        });
    }

 

 

1분 퀴즈) 다음 설명 중 옳은 것을 모두 고르세요.

① 모달은 웹 페이지 내부에서 상위 레이어를 띄우는 방식으로 사용하는 창이다.

 show.bs.modal 이벤트는 모달이 보여진 다음 수행된다.

③ HTML의 data-* 속성은 HTML 요소에 추가 정보를 저장하고 싶을 때 사용한다.

④ 이벤트 핸들러란 특정 이벤트를 처리하는 함수다.

 JSON.stringify()는 문자열을 입력받아 자바스크립트 객체로 반환한다.

답: 1, 3, 5

 

 

19장 웹 페이지에서 댓글 삭제하기

 

댓글 삭제는

1. 댓글 [삭제] 버튼 추가

2. [삭제] 버튼 클릭 시 REST API 요청 보내기 방식 순으로 진행 예정이다.

 

먼저 뷰 페이지에 삭제 버튼을 추가했다.

[ _list.mustache ]

수정 버튼 태그 아래에 삭제 버튼 태그 추가

<!-- 댓글 삭제 버튼 -->
<button type="button" class="btn btn-sm btn-outline-danger comment-delete-btn"
                        data-comment-id="{{id}}">삭제</button>

 

댓글 삭제 스크립트

[ _list.mustache ]

<!-- 댓글 삭제 -->
<script>
    {
        // 삭제 버튼 선택
        const commentDeleteBtn = document.querySelectorAll(".comment-delete-btn");
        // 삭제 버튼 이벤트 처리
        commentDeleteBtn.forEach(btn => {
            btn.addEventListener("click", (event) => {       // event 객체 받아오기
                // 이벤트 발생 요소 선택
                const commentDeleteBtn = event.target;      // [삭제]버튼 변수화
                // 삭제 댓글 id 가져오기
                const commentId = commentDeleteBtn.getAttribute("data-comment-id"); // id 가져오기
                console.log(`삭제 버튼이 클릭 : ${commentId}번 댓글`);
                // 삭제 REST API 호출
                const url = `/api/comments/${commentId}`;
                fetch(url, {
                    method: "DELETE"
                }).then(response => {
                    // 댓글 삭제 실패 처리
                    if (!response.ok) {
                        alert("댓글 삭제 실패...!");
                        return;
                    }
                    // 삭제 성공 시 댓글을 화면에서 지우고 메시지 창 띄우기
                    const target = document.querySelector(`#comments-${commentId}`);
                    target.remove();
                    const msg = `${commentId}번 댓글을 삭제했습니다.`;
                    alert(msg);
                    // 현재 페이지 새로 고침
                    window.location.reload();
                });
            });
        });
    }
</script>
반응형