[팀프로젝트] 영화 상세페이지 - 페이지별 리뷰 댓글 수정 및 삭제 (3)

liinyeye·2024년 5월 8일
0

Project

목록 보기
7/44

이전에 만들어뒀던 댓글 생성하는 기능에 이어 수정 및 삭제 기능도 추가로 구현해야 했다. 처음에는 댓글을 삭제하고 수정하는 함수를 어디에 넣어야할지 잘 가늠이 되지 않았는데, 튜터님께 조언을 구해 로직을 이해할 수 있었다.

결국 댓글을 생성할 때 삭제되거나 수정된 댓글을 반영해 화면에 그려줘야하기 때문에 generateComment 함수 안에서 이 모든 것이 이뤄져야한다는 것을 알게 됐다. 여기서 함수 이름을 generate으로 적어두어서 자꾸 헷갈리는 부분이 있었는데, 이런 로직이라면 paintComment가 더 적합하다고 생각했다. 함수 이름 짓기의 중요성을 다시 한 번 깨닫게 됐다.

댓글 수정 및 삭제

초기 코드는 댓글 수정 및 삭제 시 프롬프트 창을 띄워 비밀번호와 수정할 내용을 입력하는 방식이었는데, 모달창을 띄우자는 아이디어를 내어 다른 팀원분이 모달창으로 수정해서 구현해주셨다.

댓글 수정 와이어프레임 제안

  • 모달창 띄우기
  • 기존 댓글 display : hidden;으로 가려두고 해당 자리에 새로운 인풋 댓글수정창 넣기

로컬스토리지 데이터 다루기

// 로컬스토리지 데이터 불러오기
function loadComments(movieId) {
  const comments = getComments(movieId);
  generateComment(comments);
}

// 로컬스토리지에 데이터 저장하기
function saveComments(movieId, comments) {
  localStorage.setItem(`comments_${movieId}`, JSON.stringify(comments));
}

//로컬스토리지에서 데이터 가져오기
function getComments(movieId) {
  const savedComments = localStorage.getItem(`comments_${movieId}`);
  return savedComments ? JSON.parse(savedComments) : [];
}

댓글 삭제 (Delete)

초기에 시도한 삭제 시 구현하려고 했던 로직은 기존의 저장된 데이터 배열을 forEach로 돌면서 클릭 이벤트가 적용된 요소의 아이디와 삭제한 요소의 아이디값을 확인해주는 것이었다. 새로운 배열을 선언하고 지워지지 않은 나머지 요소들을 새로운 배열에 넣어주어, 다시 그 배열을 setItem을 통해 localStorage에 넣어주려 했다.

function deleteComment() {
  // 화면에서 댓글 지워주기
  const li =
      event.target.parentElement.parentElement.parentElement.parentElement;
  li.remove();
      
  //로컬스토리지에서 데이터 지워주기
  const deletedId = 124; // 랜덤 아이디 부여 가정

  const newComments = [];
  localStorage.getItem("comments").forEach(element => {
    if (element.id !== deletedId) {
        newComments.push(element)
    }
  });

  localStorage.setItem("comments", newComments)
     
}

오류 및 해결

삭제는 잘 되었지만 새로고침 시 로컬스토리지에 있는 데이터가 원하는대로 업데이트되지 않았고 push를 통해 넣어줄 경우, forEach를 돌아가면서 배열에 push를 해줄 경우 원하는 순서대로 들어가지 않을 것이라 판단해서 방식을 바꿔filter를 사용하기로 했다.

// getComments함수를 통해 받아온 데이터의 배열
let commentDrawn = getComments(movieId, comments);

//댓글 삭제하기 (모달 수정)
  const modal = document.getElementById("delmodal");
  const confirmBtn = document.getElementById("delconfirmBtn");
  const passwordInput = document.getElementById("delpasswordInput");

  const deleteComment = (event) => {
    // 모달창 닫기
    const closeModal = () => {
      modal.style.display = "none";
      passwordInput.value = "";
      commentInput.value = "";
    };

    const li =
      event.target.parentElement.parentElement.parentElement.parentElement;

    commentDrawn.forEach((element) => {
      let cancelSwitch = Boolean;
      if (li.getAttribute("id") === String(element.Id)) {
        modal.style.display = "block";

        confirmBtn.onclick = () => {
          const passwordTry = passwordInput.value;
          if (passwordTry === element.Password) {
            cancelSwitch = true;
            li.remove();

            const newComments = commentDrawn.filter(
              (element) => element.Id !== li.getAttribute("id")
            );
            saveComments(movieId, newComments);
            alert("삭제되었습니다.");
            passwordInput.value = "";
            location.reload();
          } else {
            cancelSwitch = false;
            passwordInput.value = "";
            alert("비밀번호가 틀렸습니다. 다시 입력해주세요.");
          }
          modal.style.display = "none";
        };

        modal.querySelector(".close").onclick = () => {
          modal.style.display = "none";
          cancelSwitch = false;
        };
      }
    });

    // 모달 외부 클릭 시 닫기
    window.onclick = (event) => {
      if (event.target === modal) {
        closeModal(); // 모달 닫기
      }
    };
  };

  const deleteBtn = document.querySelectorAll(".delete");
  deleteBtn.forEach((element) =>
    element.addEventListener("click", deleteComment)
  );

const newComments = commentDrawn.filter( (element) => element.Id !== li.getAttribute("id") );

filter로 기존의 배열에서 삭제된 요소를 제외한 나머지를 새로운 newComments 배열을 만들어주고,

saveComments(movieId, newComments)로 새로운 배열을 다시 로컬스토리지에 저장해줘 데이터를 업데이트해준다.

댓글 수정 (Edit/Update)

// 댓글 수정 (모달 수정)
  const editComment = (e) => {
    const commentBox = e.target.parentNode.parentNode.parentNode.parentNode;

    const modal = document.getElementById("modal");
    const passwordInput = document.getElementById("passwordInput");
    const commentInput = document.getElementById("commentInput");
    const submitBtn = document.getElementById("submitBtn");
    const cancelBtn = document.getElementById("cancelBtn");

    modal.style.display = "block"; // 모달창 열기

    // 모달창 닫기
    const closeModal = () => {
      modal.style.display = "none";
      passwordInput.value = "";
      commentInput.value = "";
    };

    // 확인 버튼 클릭 시
    submitBtn.onclick = () => {
      const passwordEditTry = passwordInput.value;
      commentDrawn.forEach((element) => {
        if (commentBox.getAttribute("id") === String(element.Id)) {
          if (passwordEditTry === element.Password) {
            element.Review = commentInput.value;
            saveComments(movieId, commentDrawn);
            alert("저장되었습니다.");
            closeModal(); // 모달 닫기
            location.reload(); // 페이지 새로고침
          } else {
            alert("비밀번호가 일치하지 않습니다.");
            closeModal(); // 모달 닫기
          }
        }
      });
    };

    // 취소 버튼 클릭 시
    cancelBtn.onclick = () => {
      closeModal(); // 모달 닫기
    };

    // 모달 외부 클릭 시 닫기
    window.onclick = (event) => {
      if (event.target === modal) {
        closeModal(); // 모달 닫기
      }
    };
  };

  const editBtn = document.querySelectorAll(".edit");
  editBtn.forEach((element) => element.addEventListener("click", editComment));

댓글을 수정할 때는 로컬스토리지의 value에 있는 객체와 배열은 그대로 유지되면서 내용만 업데이트해주는 것이기 때문에
element.Review = commentInput.value; 로 input.value만 변경해 내용을 업데이트 해주고 이 값이 있는 기존 배열을 다시
saveComments(movieId, commentDrawn); 를 통해 로컬스토리지에 저장해줬다.


댓글 삭제와 수정은 새로운 배열을 인자로 넣어주느냐 아니느냐에 차이가 있었다.

궁금한 점과 부족한 내용

  • filter 함수를 통해 새로운 배열을 저장 시 비밀번호를 누르는 과정없이 댓글을 한 번에 여러 개 삭제했을 때, filter된 요소가 누적되지 않고 로컬스토리지에 계속 새롭게 업데이트 되어 새로고침 시 마지막에 삭제한 댓글만 삭제되는 문제가 있었다.
    이번 프로젝트에서는 비밀번호를 누르고 맞을 경우 삭제하는 유효성 검사 과정을 넣어서, 사실 상 댓글을 한 번에 여러 개 지울 일은 없다보니 당장은 해당 오류를 넘겼지만 이런 경우 어떤 방식으로 배열을 저장해야할지 궁금했다.
profile
웹 프론트엔드 UXUI

0개의 댓글