[TIL] 영화 검색 사이트 만들기

·2023년 10월 19일
0

TIL

목록 보기
10/85
post-thumbnail

📌 자바스크립트 개인 과제

  • 영화정보 Open API 인 THDM(The Movie DB)를 사용하여 영화 검색 사이트 만들기!
  • 필수 요구사항
    1. jQuery 라이브러리 사용 없이 Vanilla JavaScript로 구현하기
    2. TMDB Open API를 이용하여 인기영화 데이터 가져오기
    3. 영화 정보 카드 리스트 UI 구현
    • TMDB에서 받아온 데이터를 브라우저에 카드 형태의 데이터로 보여준다.
    • 카드에는 title, overview, poster_path, vote_average 의 4가지 정보가 필수로 들어간다.
    • 카드 클릭 시에 클릭한 영화 id 를 나타내는 alert 창을 띄운다.
    1. 영화 검색 UI 구현
  • 선택 요구사항
    • CSS : flex, grid 사용하기
    • 웹사이트 랜딩 또는 새로고침 후 검색 입력란에 커서 자동 위치시키기
    • 대소문자 관계없이 검색 가능하게 하기
    • 키보드 enter키를 입력해도 검색 버튼 클릭한 것과 동일하게 실행시키기

자바스크립트 문법 강의를 듣고 어제부터 드디어 개인 과제가 시작되었다!
아직 디자인적인 부분은 완성하지 않았지만 얼추 기능적인 부분은 모두 구현하였다!
어제는 영화 API를 받아와서 화면에 뿌려주는 부분을 완성하였고, 오늘은 영화 카드 클릭 시 영화 id를 alert 하는 부분, 그리고 가장 중요한 영화 검색 기능을 구현해보았다.

  • 영화 정보 카드 리스트 구현
  • 카드 클릭 시 클릭한 영화 id 나타내는 alert 창 구현

영화 API를 가져오고, 화면에 뿌려주고, 카드별로 각각 alert 창 띄우는 것까지는 어제 크~게 무리 없이 했는데, 오늘 검색 기능을 구현하는 부분에서 애를 먹었다.

영화 카드 생성하기!

fetch(
  "https://api.themoviedb.org/3/movie/top_rated?language=en-US&page=1",
  options
)
  .then((response) => response.json())
  .then((response) => {
    console.log(response);
    const result = response.results;
    result.forEach((movie) => {
      addMovie(movie);
    });
  })
  .catch((err) => console.error(err));

function addMovie(movie) {
  const base_url = "https://image.tmdb.org/";
  const file_size = "t/p/w500";
  const file_path = movie.poster_path;
  const div = document.createElement("div");
  div.classList.add("movie-card");

  div.innerHTML = `<div class="movie-card__poster">
  <img src=${base_url}${file_size}${file_path} /></div>
<div class="movie-card__content">
  <div class="movie-card__title">${movie.title}</div>
  <div class="movie-card__overview">${movie.overview}</div>
  <div class="movie-card__vote-average">Ratings : ${movie.vote_average}</div>
</div>`;
  div.addEventListener("click", () => alert(`영화 id : ${movie.id}`));
  div.id = movie.id;
  movieCards.append(div);
}
  1. 우선 fetch 를 통해 인기 영화 API 를 가져오고, 가져온 값 중 필요한 부분만 뽑아 addMovie()함수를 forEach문을 통해 반복적으로 돌며 카드를 20장 생성하였다.
    그리고addMovie() 함수 실행할 때 각 카드에 addEventListener 를 추가하여 클릭 이벤트가 발생할 때 영화 id 에 대한 alert이 뜨도록 했다.

  2. 각 카드는 movie-card라는 클래스명을 가지고 있는데, 이 클래스명을 갖는 element를 querySelecorAll로 가져오고, 그안에 있는 영화 제목 값을 후루룩 뽑아와서 영화 제목 값이 내가 input에 입력한 값을 포함하고 있지 않으면 그 element들에 hidden이라는 클래스를 부여해야지! 가 첫 번째 아이디어 였다.

  3. 그래서 일단 movie-card 라는 클래스명을 갖는 친구들을 뽑아오자. 해서 아래 코드를 실행했다.

const movieCards = document.querySelector(".movie-cards");
const movieCard = movieCards.querySelectorAll(".movie-card");

외않되? 🤯

원래 search.js 파일을 따로 생성해서 값을 읽어오려고 했는데 아무리 해도 값을 읽어오지 못했다. 카드 각각 id에 movie.id 값을 주어서 getElementById 로 읽어오려고 시도해도 값을 읽어오지 못했다.. 여기서 막혀서 결국 튜터님을 찾아갔다.

노력의 흔적

해결 과정 🤗

fetch(
  "https://api.themoviedb.org/3/movie/top_rated?language=en-US&page=1",
  options
)
  .then((response) => response.json())
  .then((response) => {
    console.log(response);
    const result = response.results;
    result.forEach((movie) => {
      addMovie(movie);
    });
  })
  .catch((err) => console.error(err));

값을 읽어오지 못했던 이유는 fetch를 통해 API 를 호출하고 나서 .then 안에 있는 addMovie() 함수를 다 ~ 실행하고 난 후에 DOM Tree가 완성되는데, DOM Tree 가 완성 되기도 전에 movie-card 라는 클래스명을 갖는 element를 가져오려고 했던 것이었다.. 😇 그러면 addMovie() 를 다 돌고 나서 (돔 트리 완성 후) 값을 읽어오려먼 어떻게 하는지 여쭤봤다.. 답은 간단했다.

fetch(
  "https://api.themoviedb.org/3/movie/top_rated?language=en-US&page=1",
  options
)
  .then((response) => response.json())
  .then((response) => {
    console.log(response);
    const result = response.results;
    result.forEach((movie) => {
      addMovie(movie);
    });
  })
  .then(searchMovie) // 이걸 몰라서 고통받음.
  .catch((err) => console.error(err));

하단에 세번째then 을 또 작성해주면 두번째 then 안에 있는 코드를 다 ~ 실행하고 난 후 세번째 then 안에 있는 함수를 실행한다. 세번째 then 안에 searchMovie() 라는 함수를 넣어서 그 함수 안에 movie-card 클래스명을 갖는 elements를 긁어오니 잘 가져와졌다!! 하...

function searchMovie() {
  const movieCard = movieCards.querySelectorAll(".movie-card");
  const searchValue = document.getElementById("search__value");
  const searchBtn = document.querySelector(".search__btn");

  function handleSearch(e) {
    e.preventDefault();
    let value = searchValue.value;
    movieCard.forEach((element) => {
      element.classList.remove("hidden");
      let movieTitle = element.childNodes[2].childNodes[1].innerText;
      if (!movieTitle.toLowerCase().includes(value)) {
        element.classList.add("hidden");
      }
    });
  }
  searchBtn.addEventListener("click", handleSearch);
}

searchMovie() 함수는 위처럼 구현했다. movie title 에 input value 값이 포함되는지 여부를 파악하여 포함하지 않는 element 에 hidden 클래스를 추가했다. (display : none) 이를 위해 includes 라는 메서드를 활용했는데 (대소문자 관계 없이 검색하기 toLowerCase() 사용) 뭔가 RegExp(정규표현식) 을 활용하는 더 좋은 방법이 있을 것 같은데 잘 모르겠다. 더 찾아봐야지. 그리고 기능은 잘 동작하지만, 클린 한 코드는 아닌 것 같기도 하다. 좀 더 가독성 있게 다듬어봐야 겠다.

피드백 (추가)

개인과제를 제출하고 며칠 뒤에 개인별 피드백이 메일로 전송되었다.

이미지 파일 경로 예시에 있던 base_url, file_size, file_path라는 이름을 변수명으로 사용했더니 camelCase로 사용하라는 피드백을 받았다. (전체 코드에서 저 세개만 snake_case 였는데 저걸 보시다니😂) 일일이 코드리뷰를 해주시는 걸 보고 약간 놀랐다(?) 대부분 좋은 피드백이라 감사하지만, 아직도 갈길이 구만리.. 피드백을 밑거름으로 더욱 성장해야겠다.

느낀점

진짜 진짜 도무지 모르겠을 때만 튜터님을 찾아가는데, 갔다오면 늘 해결이 되어있어서 진작 찾아갈걸 하는 생각이 든다.ㅎ 그렇지만 머리 싸매고 고민했던 시간들이 있어야 뭐가 안되는지 질문을 명확하게 할 수 있다고 생각한다.
그리고 물고기를 잡아주시는게 아니라 물가 근처에 데려다주시기만 하는데 그 도움을 받아 혼자 문제를 해결했을 때 짱 뿌듯함..😂

내일 할일

  • 웹사이트 랜딩 후 검색 입력란에 커서 자동 위치시키는 기능 구현해보기
  • CSS 다듬기 ( 좀 예쁘게 해봐야지.. )
profile
느리더라도 조금씩, 꾸준히

0개의 댓글