TACO 프로젝트 회고록(JS, Thymeleaf 작업)2

윤현우·2023년 8월 6일
0

TACO 프로젝트 회고록

목록 보기
28/31
post-thumbnail

회원가입/ 로그인 기능을 끝마친 후 나는 게시글 상세화면에 대한 js작업과 thymeleaf작업을 진행하였다.

게시글 쓰는 페이지는 다른 팀원이 하기로 하고 나는 메인페이지에서 게시글을 클릭했을 때 나오는 게시글 상세화면을 만들었다.

주요 기능

  1. 해당 게시글이 자신이 쓴 게시글이라면 게시글 수정 및 삭제 버튼 활성화

  2. 해당 게시글 thymeleaf 작업

  3. 해당 게시글의 댓글 thymeleaf 작업

1. 해당 게시글이 자신이 쓴 게시글이라면 수정 및 삭제 버튼 활성화

이 부분이 사실 게시글 상세화면 부분에서 가장 어려운 부분이라고 생각한다.

우선 게시글 상세화면은 로그인세션이 있는 상태, 로그인이 되어있지 않은 상태 둘다 해당 페이지를 들어올 수 있기 때문에 게시글 수정 및 삭제 버튼은 게시글의 주인이 로그인하지 않는이상 활성화 되면 안된다.

이 부분을 어떻게 하면 좋을까 곰곰히 생각해보았다.

해당 게시글의 index와 로그인된 유저의 index가 같으면 해당 버튼들이 활성화 되어야 한다.

그래서 게시글을 가져올때의 메서드에 thymeleaf값 하나를 가져와서 만들기로 생각했다.(나중에 좋은 방법이 생각났다.)

@GetMapping("/post/{postId}")
    public String read(HttpSession session, @PathVariable(name = "postId") Long postId, Model model) {
        Long userIndex = (Long) session.getAttribute("userIndex");
        model.addAttribute("userIndex", userIndex);
      
        // 게시글 model
        Optional<PostEntity> post = postService.read(postId);
        post.ifPresent(o -> model.addAttribute("post", o));
        
        // 세션을 가져와서 만약 게시글, 댓글 userIndex와 같다면
        // 1을 출력해 수정 및 삭제 버튼 활성화 
        // 로그인 했지만, 다르면 0 
        // 로그인하지 않았다면, 2 출력
        // 수정 필요
        Integer checkedUserIndexForPost = 0;
        if(userIndex != null){
            if(userIndex == post.get().getUserIndex()){
                // 게시글, 댓글, 세션이 같으면
                checkedUserIndexForPost = 1;
                model.addAttribute("checkIndexForPost", checkedUserIndexForPost);
            } else if(userIndex != post.get().getUserIndex()){
                checkedUserIndexForPost = 2;
                model.addAttribute("checkIndexForPost", checkedUserIndexForPost);
            }
        }
        else if(userIndex == null){
            model.addAttribute("checkIndexForPost", checkedUserIndexForPost);
        }
        
        return "post_detail";
    }

가장 먼저 해당 게시글을 가져와 model화 해준다.

그 후 userIndex가 있을 때 없을 때를 비교하고 없다면 2,
로그인하여 userIndex가 있지만, 게시글 index와 다르다면 0,
해당 게시글이 로그인한 사용자의 게시글이면 1을 반환하여 model에 넣어주었다.

이 값을 js에서 받아서 확인하는 방식으로 진행하였다.

$(document).ready(() => {
  var index_button = $("input[name=index_button]").val();
  if (index_button == 1) {
    console.log(index_button);
    $(".deleteEdit").css("display", "flex");
  }
});

$("input[name=index_button]").val();

이 부분은 해당 타임리프 값을 input hidden 값으로 html에 집어넣어 해당 value를 가져오게 만든 것이다.

<input type="hidden" name="index_button" th:value="${checkIndexForPost}"/>

개선사항

사실 어짜피 로그인세션의 userIndex를 model화 한다면, 위의 방법보다, userIndex의 value값을 가져오고, thymeleaf로 가져온 게시글 model에서 userIndex를 뽑아와 그 둘을 비교시켜도 되었을 것이다.

그것이 유지보수에 좀 더 도움이 되었을 것이다.

나중에 해당 프로젝트를 리펙토링하게 된다면 이 부분을 고쳐주고 싶다.

2. 해당 게시글 thymeleaf 작업

해당 thymeleaf 작업은 너무 쉬워서 넘어가겠다.

3. 해당 게시글의 댓글 js, thymeleaf 작업

댓글 작성은 form 태그를 이용하여 구현하였다.

여기서 댓글을 작성한 후 해당 댓글을 보게 되면 만약 로그인한 유저가 해당 댓글을 썼다면, 수정 및 삭제 버튼이 생긴다.

이 부분을 위에 게시글 수정 삭제 버튼의 개선사항으로 만들어 보았다.

thymeleaf의 th:style을 이용하여 만약 같다면 해당 display를 활성화 시키는 방법으로 만들었다.

<div
  class="deleteEditC"
  th:style="${reply.replyUserIndex == userIndex ? 'display:flex' : 'display:none'}"
>
	<button class="editC">수정</button>
	<form
 		th:action="@{/reply/delete/{replyIndex}(replyIndex=${reply.replyIndex})}"
 		method="post"
	>
	<input type="hidden" name="_method" value="delete" />
	<button class="deleteC">삭제</button>
	</form>
</div>

각각의 댓글의 userIndex를 가져와 만약 로그인세션의 userIndex와 같다면 해당 버튼들을 활성화 하고 다르면 비활성화 하게 만들었다.

댓글 수정은 ajax를 이용하여 비동기 방식으로 구현하였다.

document.addEventListener("DOMContentLoaded", function () {
  // Addeventlisteners "수정" 버튼
  function handleEditClick(event) {
    const commentBox = event.target.closest(".commentBox");
    const commentText = commentBox.querySelector(".comment");
    const commentContent = commentText.innerText;

    const textarea = document.createElement("textarea");
    textarea.classList.add("editTextarea");
    textarea.name = "editedComment";
    textarea.value = commentContent;

    const saveButton = document.createElement("button");
    saveButton.classList.add("saveC");
    saveButton.innerText = "저장";

    const editDeleteContainer = commentBox.querySelector(".deleteEditC");
    editDeleteContainer.innerHTML = "";
    commentText.innerHTML = "";
    commentText.appendChild(textarea);
    editDeleteContainer.appendChild(saveButton);

    //기능 삭제
    event.target.removeEventListener("click", handleEditClick);

    saveButton.addEventListener("click", function () {
      const editedComment = textarea.value;
      var reply_index = $("input[name=reply_index]").val();

      $.ajax({
        url: "/reply/edit/" + reply_index,
        type: "POST",
        data: {
          replyDescription: editedComment,
        },
        success: function (response) {
          console.log("업데이트에 성공했습니다.");

          commentText.innerText = editedComment;
          editDeleteContainer.innerHTML = "";

          const editButton = document.createElement("button");
          editButton.classList.add("editC");
          editButton.innerText = "수정";

          const deleteButton = document.createElement("button");
          deleteButton.classList.add("deleteC");
          deleteButton.innerText = "삭제";

          editDeleteContainer.appendChild(editButton);
          editDeleteContainer.appendChild(deleteButton);

          //다시 적용
          editButton.addEventListener("click", handleEditClick);
        },
      });
    });
  }

  const editButtons = document.querySelectorAll(".editC");
  editButtons.forEach((button) => {
    button.addEventListener("click", handleEditClick);
  });
});

수정 버튼을 눌렀을 때, handleEditClick함수가 실행되어 textarea와 저장 버튼을 추가 시킨뒤 저장 버튼을 눌렀을 때 ajax로 수정이 가능하게 만들었다.

삭제 버튼은 form 태그를 이용하여 바로 삭제 가능하게 구현하였다.

profile
개발자가 되는 그날까지

0개의 댓글