댓글 수정 with JS

OneTwoThree·2022년 10월 24일
0

유튜브

댓글 수정 페이지를 작성해보자

댓글이 표시되는 부분에 닉네임 옆에 수정 버튼을 만들고 클릭해서 수정할 수 있게 하자.

버튼을 누르면 모달을 띄워서 수정할 내용을 입력받고 수정 완료를 누르면 반영되게 한다.
모달은 부트스트랩에서 제공하는 디자인인데 이런 모양이다.

이런 식으로 표시되게 한다.
부트스트랩에서 모달을 사용하는 예시 코드를 제공한다.
그것을 참고하며 코드를 작성하면 된다.

<div id="comments-list">
    {{#commentDtos}}
        <div class="card m-2" id="comments-{{id}}">
            <div class="card-header">
                {{nickname}}
                <!-- Button trigger modal -->
                <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" 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 form-control-sm" id="edit-comment-nickname">
                    </div>
                    <!-- 댓글 본문 입력 -->
                    <div class="mb-3">
                        <label class="form-label">댓글 내용</label>
                        <textarea type="text" class="form-control form-control-sm" 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="button" class="btn btn-outline-primary btn-sm" id="comment-update-btn">수정 완료</button>
                </form>
            </div>
        </div>
    </div>
</div>
<!-- 모달 이벤트 처리 -->
<Script>
{
  // 모달 요소 선택
  const commentEditModal = document.querySelector("#comment-edit-modal");
  // 모달 이벤트 감지
  commentEditModal.addEventListener("show.bs.modal", function(event) {
    // 트리거 버튼 선택
    const triggerBtn = event.relatedTarget;
    // 데이터 가져오기
    const id = triggerBtn.getAttribute("data-bs-id");
    const nickname = triggerBtn.getAttribute("data-bs-nickname");
    const body = triggerBtn.getAttribute("data-bs-body");
    const articleId = triggerBtn.getAttribute("data-bs-article-id");
    //console.log(`${id}, ${nickname}, ${body}, ${articleId}`);
    // 데이터를 반영
    document.querySelector("#edit-comment-nickname").value = nickname;
    document.querySelector("#edit-comment-body").value = body;
    document.querySelector("#edit-comment-id").value = id;
    document.querySelector("#edit-comment-article-id").value = articleId;
  });
}
{
  // 수정 완료 버튼
  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 호출 - fetch()
    const url = "/api/comments/" + comment.id;
    fetch(url, {
      method: "PATCH",
      body: JSON.stringify(comment),
      headers: {
        "Content-Type": "application/json"
      }
    }).then(response => {
      // http 응답 코드에 따른 메시지 출력
      const msg = (response.ok) ? "댓글이 수정 되었습니다." : "댓글 수정 실패..!";
      alert(msg);
      // 현재 페이지를 새로고침
      window.location.reload();
    });
  });
}
</script>

_list.mustache의 전체 코드다
한 부분씩 차례로 확인해보자

<div id="comments-list">
    {{#commentDtos}}
        <div class="card m-2" id="comments-{{id}}">
            <div class="card-header">
                {{nickname}}
                <!-- Button trigger modal -->
                <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>

닉네임 옆에 수정 버튼을 넣어줬다.
부트스트랩을 이용한 모달 창을 띄우기 위한 버튼이다.
버튼의 속성값을 보면 data-bs-id, data-bs-nickname.. 등이 있다.

   @GetMapping("/articles/{id}")
    public String show(@PathVariable Long id, Model model){
        log.info("id = "+id);

        //1. id로 데이터를 가져옴
        //orElse로 해당 id값이 없다면 null을 반환
        Article articleEntitiy = articleRepository.findById(id).orElse(null);
        List<CommentDto> commentDtos = commentService.comments(id);


        //2. 가져온 데이터를 모델에 등록
        model.addAttribute("article",articleEntitiy);
        model.addAttribute("commentDtos",commentDtos);



        //3. 보여줄 페이지를 설정
        return "articles/show";
    }

ArticleController에서 이렇게 commentDtos라는 이름으로 CommentDto의 리스트를 모델에 등록했었고 이 값을 뷰페이저에서 사용했다.

{{#commentDtos}}로 감싸진 부분 내에서 모델의 데이터 중 원하는 필드를 속성값으로 넣었다. 이렇게 한 이유는 아래 JS 코드에서 버튼을 누르면 모달 창을 띄우고 모달 창의 닉네임, 댓글 내용 부분에 전에 입력했던 닉네임과 댓글 내용을 넣고, hidden form에는 id 같은 내용을 넣어줄거라서 그때 쓰기 위해 속성값으로 넣어놓은 것이다.

<!-- 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" 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 form-control-sm" id="edit-comment-nickname">
                    </div>
                    <!-- 댓글 본문 입력 -->
                    <div class="mb-3">
                        <label class="form-label">댓글 내용</label>
                        <textarea type="text" class="form-control form-control-sm" 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="button" class="btn btn-outline-primary btn-sm" id="comment-update-btn">수정 완료</button>
                </form>
            </div>
        </div>
    </div>
</div>

이 부분은 모달 창에 해당하는 부분이다.
부트스트랩을 이용해서 모달 창을 만들었고, 안에는 입력 폼을 넣어줬다.
히든 인풋에는 comment-id와 article-id가 있다.

<Script>
{
  // 모달 요소 선택
  const commentEditModal = document.querySelector("#comment-edit-modal");
  // 모달 이벤트 감지
  commentEditModal.addEventListener("show.bs.modal", function(event) {
    // 트리거 버튼 선택
    const triggerBtn = event.relatedTarget;
    // 데이터 가져오기
    const id = triggerBtn.getAttribute("data-bs-id");
    const nickname = triggerBtn.getAttribute("data-bs-nickname");
    const body = triggerBtn.getAttribute("data-bs-body");
    const articleId = triggerBtn.getAttribute("data-bs-article-id");
    //console.log(`${id}, ${nickname}, ${body}, ${articleId}`);
    // 데이터를 반영
    document.querySelector("#edit-comment-nickname").value = nickname;
    document.querySelector("#edit-comment-body").value = body;
    document.querySelector("#edit-comment-id").value = id;
    document.querySelector("#edit-comment-article-id").value = articleId;
  });
}

이제 JS 로 모달 이벤트를 처리하는 부분이다.
먼저 querySelector로 모달 트리거 버튼을 변수로 가져왔다.
해당 버튼에 addEventListener로 리스너를 등록해주는데, 이벤트는 "show.bs.modal"로 부트스트랩 홈페이지에 가면 이렇게 작성하라고 가이드가 있다.
리스너는 event를 매개변수로 받아서 이벤트가 발생한 대상을 relatedTarget으로 가져온다.
그러면 사용자가 누른 모달 트리거 버튼을 가져온 것이고 위에서 이 버튼의 속성값을 지정한 것을 지금 사용한다.
id, nickname, body 이런 것들을 가져와서 변수로 저장한 후에 이 데이터를 입력 폼에 표시해주기 위해 마찬가지로 querySelector로 폼의 input 요소들을 가져와서 value에 넣어준다.
여기까지 하면 모달 트리거 버튼을 눌렀을 때 모달 창이 표시되고 닉네임, 댓글 내용에 기존 사용자가 입력한 값이 표시된다.

{
  // 수정 완료 버튼
  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 호출 - fetch()
    const url = "/api/comments/" + comment.id;
    fetch(url, {
      method: "PATCH",
      body: JSON.stringify(comment),
      headers: {
        "Content-Type": "application/json"
      }
    }).then(response => {
      // http 응답 코드에 따른 메시지 출력
      const msg = (response.ok) ? "댓글이 수정 되었습니다." : "댓글 수정 실패..!";
      alert(msg);
      // 현재 페이지를 새로고침
      window.location.reload();
    });
  });
}
</script>

JS코드의 다음 블록 부분이다.
이제 수정 완료 버튼을 누르면 이벤트 처리를 해줘야 한다.

// 수정 완료 버튼
  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
    };

querySelector로 수정 완료 버튼을 가져오고, addEventListener로 리스너 등록
수정 댓글 객체를 생성해준다.

// 수정 REST API 호출 - fetch()
    const url = "/api/comments/" + comment.id;
    fetch(url, {
      method: "PATCH",
      body: JSON.stringify(comment),
      headers: {
        "Content-Type": "application/json"
      }
    }).then(response => {
      // http 응답 코드에 따른 메시지 출력
      const msg = (response.ok) ? "댓글이 수정 되었습니다." : "댓글 수정 실패..!";
      alert(msg);
      // 현재 페이지를 새로고침
      window.location.reload();
    });

수정 REST API를 호출하기 위해 fetch()를 호출한다
첫번째 매개변수로 url을 전달하고, 두번째 매개변수로 어떤 내용을 전달할지 작성한다.
PATCH 메소드로 만든 JS 객체를 JSON 데이터로 바꿔서 보내준다.
응답을 등록하기 위해 then(response => 로 등록해준다
response가 ok인지 아닌지에 따라 msg를 결정하고 alert으로 출력해준다.
그리고 페이지를 새로고침해서 변경사항이 표시되도록 한다.

모달 창, 기존에 입력한 내용이 표시된다.

수정

alert 창

수정됨

요약

  • _list.mustache에 수정 버튼을 추가
  • 부트스트랩 페이지의 Varying modal content 부분에서 모달 창에 데이터를 가져오는 법을 볼 수 있다.
  • 버튼의 속성값에 데이터를 넣고 JS로 속성값을 가져옴(트리거 버튼을 가져와서 버튼의 속성값을 가져옴)
  • 수정 버튼을 누르면 요청을 REST API로 보냄

0개의 댓글