어제 상세페이지로 이동해서 포스터이미지 불러오는 것 까지는 완성했고, 나머지는 다른 조원들이. 나는 localStorage를 활용한 리뷰 작성 기능을 담당했다. 예전에 localStorage를 활용하여 to-do list를 만들어 본 경험이 있어서 코드를 작성하는데 도움이 되었다.
아직 CSS 작업을 거의 하지 않은 상태라 디자인 끔찍 그잡채🫠
감안하고 봐주시길ㅎ
리뷰 작성 시 validation check(유효성 검사)를 위해 각 태그에 minlength
, required
를 넣어주었다.
별점 선택을 위해 select
태그를 사용했는데 required
를 넣었음에도 불구하고 별점 선택을 하지 않고 제출해도 계속 저장이 되어버리는 현상이 발생했다.
열심히 검색해서 별점 선택 option
에 value=""
를 해주면 되는 걸 알아냄.ㅎ 별거 아닌데 찾는데 시간걸렸다. 😇
<select class="review__star" id="star" required>
<option selected value="">별점 선택</option>
<option value="⭐️">⭐️</option>
<option value="⭐️⭐️">⭐️⭐️</option>
<option value="⭐️⭐️⭐️">⭐️⭐️⭐️</option>
<option value="⭐️⭐️⭐️⭐️">⭐️⭐️⭐️⭐️</option>
<option value="⭐️⭐️⭐️⭐️⭐️">⭐️⭐️⭐️⭐️⭐️</option>
</select>
그리고.. 엔터키만 쳐도 등록 버튼을 누른 것처럼 동작하게 하고 싶었는데 리뷰 칸이 textarea라 엔터키를 치면 개행이 되는 것이었다.... textarea에 required 를 주었지만 textarea를 제외한 나머지 요소만 입력하고 등록해도 제출이 되어버리는 현상이..!!! 그래서 textaraa에서 엔터키를 입력했을 때에도 등록버튼을 클릭한 것 처럼 동작하게 하기 위해 다음과 같은 코드를 추가했다.
function handleTextareaEnter(e) {
if (e.key == "Enter") {
reviewSubmitBtn.click();
}
}
reviewTextarea.addEventListener("keyup", handleTextareaEnter);
폼의 입력 값에 대한 유효성 검사는 얼추 완성이 되었다.
이제 폼이 submit 되었을 때는 다음과 같은 코드를 실행한다.
let reviewStorage = [];
function saveReview() {
localStorage.setItem("review", JSON.stringify(reviewStorage));
}
function submitReview(e) {
e.preventDefault();
const reviewObj = {
name: reviewUsername.value,
password: reviewPassword.value,
star: reviewStar.value,
review: reviewTextarea.value,
id: Date.now(),
movieid: parseInt(id),
};
reviewStorage.push(reviewObj);
reviewForm.reset();
paintReview(reviewObj);
saveReview();
}
reviewForm.addEventListener("submit", submitReview);
e.preventDefault()
를 실행.id
값과 movieid
값도 주었다. (나중에 특정 리뷰만 선택해서 삭제하기 위해 id 값 Date.now()
로 할당 / 그 영화에 해당하는 리뷰만 그려주기 위해 movieid
값 할당)reviewObj
객체를 reviewStorage에 push 해 주었다.saveReview()
함수를 통해 localStorage 에 배열을 저장. 그러나 localStorage의 value 로 배열은 들어갈 수 없기 때문에 JSON.stringify
를 통해 string으로 바꿔서 저장.function paintReview(reviewObj) {
const li = document.createElement("li");
li.id = reviewObj.id;
li.classList.add("review__list");
li.innerHTML = ``
// 생략
reviewLists.append(li);
}
(여전히 디자인 끔찍스.🫠 계속 말하지만 기능 구현이 우선이라 디자인 작업 아직 안함)
const saveReviews = localStorage.getItem("review");
if (saveReviews !== null) {
//만약 reviewStorage가 localStorage에 존재하면 실행할 코드
const parsedReviews = JSON.parse(saveReviews);
reviewStorage = parsedReviews;
parsedReviews.forEach(paintReview);
}
JSON.parse
를 통해 다시 객체배열 형태로 사용할 수 있게 바꿔주었다.paintReview
함수를 실행하며 리뷰들을 그려준다.localStorage에 저장할 때 "review"라는 키로, 영화 상관없이 하나의 배열에 객체들을 저장하기 때문에 작성한 리뷰가 모든 영화의 상세페이지에서 동잃하게 보이는 문제가 발생했다. (예를 들어 '쏘우' 라는 영화의 상세페이지에 리뷰를 달았는데 '발레리나' 라는 영화의 상세페이지에도 '쏘우'에 대한 리뷰가 같이 보여짐)
이를 위해 어제 진행된 특강 내용에 배열 메서드들을 엮는 배열 체이닝이 생각났다. parsedReviews
라는 배열을 filter
메서드를 통해 객체에 저장된 movieid
와 현재 상세페이지의 id
가 일치하는 요소들만 걸러내고, 걸러진 배열 요소들만 가지고 forEach
메서드를 통해 paintReview
함수를 실행해야지!
const saveReviews = localStorage.getItem("review");
if (saveReviews !== null) {
//만약 reviewStorage가 localStorage에 존재하면 실행할 코드
const parsedReviews = JSON.parse(saveReviews);
reviewStorage = parsedReviews;
parsedReviews.filter((obj) => obj.movieid == id).forEach(paintReview); // 배열체이닝
}
배운 것 바로 써먹기~
삭제 기능도 구현은 했는데, 삭제버튼을 클릭했을 때 바로 삭제되는 것이 아니라 버튼을 클릭하면 모달 창이 생성되고, 거기서 비밀번호를 입력했을 때 해당 리뷰의 비밀번호와 일치할 경우에만 삭제하고 싶어서 이것 저것 시도해보는 중이다. 내일 다시 츄라이 해봐야지.
느낀점
- 오늘 거의 하루종일 코딩만 한 듯.. 밥도 한끼만 먹었다..
- 그래도 조금씩 진전되어가고 있어서 생각보다는(?) 힘들지 않다.
- 아침에 몸무게를 쟀는데 굉장히 오랜만에 보는 숫자가 나왔다.
- 이것이 바로 코딩 다이어트...
- 리뷰 삭제 기능에 대한 validation check를 해보고 싶은데.. 잘 안되는 중 😇