오늘 한 일
- 각 리뷰에 있는 모달 버튼 클릭 시 모달 창 생성
- 모달창에 있는 닫기 버튼 클릭 시 모달 창 닫히기
- 모달창에 있는 삭제 버튼 클릭 시 input 태그에 입력한 비밀번호 값과 해당 리뷰의 비밀번호 값과 비교 후 일치하면 삭제, 일치하지 않으면 alert 창 띄우기
- 한마디로 리뷰 삭제 기능 구현 완.
오늘은 어제에 이어서 리뷰 삭제 기능을 마무리했다.
(여전히 CSS 는 끔찍 그상태)
모달창 생성하는 건 지난 mini project에서 해 봐서 어렵지 않았다. 않을 줄 알았다. 그랬는데... 그땐 꼴랑 세개여서 그냥 세 개를 일일이 만들었고 지금은 생성되는 리뷰마다 각각의 모달창을 동적으로 생성해야하고, 각각 이벤트리스너도 달아야해서 생각보다 쉽지는 않았다. (모달창 안에 있는 input태그, 삭제, 닫기 버튼 또한..)
리뷰를 제출할 때 paintReview
함수가 실행되면서 리뷰가 생성되는데, 원래 ul 태그에 append 할 li 태그를 생성하기 위해 innerHTML을 사용하여 HTML 코드를 그대로 넣었는데, 뭔가 생성하면서 버튼마다 이벤트리스너도 달고 싶고 해서 결국 createElemet
를 사용하여 자바스크립트 코드로 다 변경하고 appendChild
로 붙여서 생성하는 방식을 선택했다. 근데 꽤 긴 라인의 HTML코드를 js로 생성하려니까 코드가 굉장히 길어졌다..ㅋㅋ
function paintReview(reviewObj) {
const li = document.createElement("li");
const openBtn = document.createElement("button");
// 생략
openBtn.addEventListener("click", openModal);
closeBtn.addEventListener("click", closeModal);
// 생략
const div1 = document.createElement("div");
div1.classList.add("hidden");
div1.classList.add("modal__container");
// 생략
li.appendChild(openBtn);
li.appendChild(div1);
reviewLists.append(li);
}
const modal = document.querySelector(".modal__container"); // querySelectorAll을 써보자
function openModal() {
modal.classList.remove("hidden");
}
function closeModal() {
modal.classList.add("hidden");
}
원래 paintReview
함수에서 리뷰를 생성하면서 이벤트리스너를 바로 달아주었는데 원하는대로 동작하지 않았다. 모달창 띄우고 input에 비밀번호 입력하고 삭제를 클릭해도 내가 선택한 리뷰가 아니라 첫번째 리뷰가 삭제되는 이슈가 발생했다.
그 이유는 paintReview
함수를 여러번 돌면서 모달도 여러 개 생기고 modal__container
라는 클래스명을 갖는 요소도 당연히 여러개 생기는데 modal__container
라는 클래스명을 갖는 요소를 querySelecter
로 가져와서 해당하는 첫번째 요소만 반환했기 때문이다.😅
querySelecterAll
로 다 가져와서 NodeLists를 반환하고 이를 다시 Array로 변환헀다. 그랬더니 연쇄적인 문제 발생.
(아까 세번째 리뷰에서 모달 버튼 클릭해도 열렸던건 세번째 리뷰에 대한 모달이 아니라 첫번째 리뷰에 대한 모달이었던 것이다. 닫기 버튼도.. 삭제버튼도.. 그래서 삭제했을 때 해당 리뷰의 비번이 아닌 첫번째 리뷰 비번을 입력하면 삭제가 되어버리는..대환장)
const modals = document.querySelectorAll(".modal__container");
let modalsArray = Array.from(modals);
function paintReview(reviewObj) {
openBtn.addEventListener("click", (e) => {
const modal = modalsArray.find(
(modal) => modal.parentElement.id === e.target.parentElement.id
);
modal.classList.remove("hidden");
});
// 생략
closeBtn.addEventListener("click", (e) => {
const modal = modalsArray.find(
(modal) =>
modal.parentElement.id ===
e.target.parentElement.parentElement.parentElement.parentElement.id // 수정 예정
);
modal.classList.add("hidden");
});
// 생략
deleteBtn.addEventListener("click", deleteReview);
}
그래서 paintReview 함수에 들어갈 모달 openBtn, closeBtn 에 대한 이벤트 함수를 위와 같이 수정했다.
modal__container
라는 클래스명을 갖는 요소를 querySelectorAll
로 다 가져오고 이 NodeList를 Array로 변환하여 modalsArray
에 저장.parentElement
한번만 타고 올라가면 li 태그에 접근할 수 있었던 반면에 closeBtn(취소버튼)은 모달창 안에 있어서 parentElement
를 총 4번이나 타고 올라가야 li 태그에 접근할 수 있었다. closest()
라는 메서드를 사용해보는게 어떻겠냐는 제안을 해주셨는데..!! 내가 찾던 놈이다.! 주말에 저거 활용해서 리팩토링 해보아야지.모달창을 만들기 전에 삭제 기능을 먼저 구현 해 놓았다.
function deleteReview(event) {
const li =
event.target.parentElement.parentElement.parentElement.parentElement; // 수정 예정
const targetReview = reviewStorage.find(
(review) => review.id === parseInt(li.id)
);
const modalInputs = document.querySelectorAll(".modal__input");
const modalInputsArray = Array.from(modalInputs);
const input = modalInputsArray.find(
(input) =>
input.parentElement.parentElement.parentElement.id ===
event.target.parentElement.parentElement.parentElement.parentElement.id // 수정 예정
);
if (targetReview.password !== input.value) {
alert("비밀번호가 일치하지 않습니다.");
input.value = "";
return;
}
reviewStorage = reviewStorage.filter(
(review) => review.id !== parseInt(li.id)
);
saveReview();
li.remove();
}
모달창 띄우고, 비밀번호 입력하고 일치하지 않을 때 alert 창 띄우고 일치하면 삭제되는 것 까지 잘 되는 것을 확인했다~!!! 으아 끝났다! 라고 생각했던 것도 잠시...
이전에 생성해 둔 리뷰들을 삭제하는 것은 잘 되는데, 방금 막 생성한 리뷰의 모달버튼을 클릭하면 동작이 되지 않는 것을 발견했다. 😂 근데 이상하게 새로고침하고 다시 버튼을 클릭하면 정상적으로 동작하는..
방금 만든 리뷰를 삭제하려고 매번 새로고침 할 수는 없는 노릇..
이 문제가 해결이 잘 안되어서 결국 튜터님을 찾아갔고, 힌트를 얻어서 곧바로 수정했다.
문제는 modalsArray
에 modal__container
라는 클래스명을 갖는 요소들이 담겨있고, 그걸 통해서 모달 오픈 버튼도 동작하는데
paintReview
함수를 실행할 때 생성된 modal은 modalsArray
에 담겨있지 않아서 발생하는 문제였다.😇
paintReview
함수에 이 한줄을 추가하니 잘 동작이 되었다. 으아와아아
modalsArray.push(div1);
남은 과제
- 모달 창 바깥부분을 클릭해도 닫히는 기능 구현
- 모달 창 input에 입력 값 없이 삭제하려고 하면 "입력값이 없습니다" alert 띄우기
- deleteReview, paintReview 함수 리팩토링. 간결하게 해보고 싶어😢
- CSS 얼른 다듬자.. 못생긴 화면에서 그만 작업하고 싶어..