Troubleshooting

Javascript "DOM" 요소를 통한 영화 검색 시스템의 오류 해결 방법

dev_gggimmmin 2024. 1. 10. 21:49
728x90

소소하게 개발중인 첫 개인과제

 

 

팀 소개 미니 프로젝트가 끝나자, Javascript 강의와 함께 찾아온 개인 과제... 

 

 

  • Javascript과정을 마무리하며, JS 문법의 핵심을 적용해 볼 수 있는 영화 검색 사이트를 제작합니다.
  • 영화정보 오픈API인 TMDB(The Movie DB)를 사용합니다.

 

 

대략적인 과제에 대한 소개는 이렇다.

 

Api 가져오기부터 카드로 정렬해서 나타내기까지 엄청 많이 헤매는 바람에 몇시간이 훌쩍 지나갔다.

그런데 정말 문제가 생겼다.

 

 Input 창에 Api에 존재하는 영화를 검색

 

검색 결과가 없습니다..

 

콘솔 창에는 Cannot read properties of null ( reading 'addEventListener' ) 이라는 메세지가 출력되었다.

 

이 오류에 대해 찾아보니

이 오류는 ' addEventListener ' 메서드를 호출하려하는데, 해당 메서드를 호출할 객체가 ' null ' 이라는 의미였다.

 

문제의 줄인 script.js:180 을 가보니 저 곳은 Enter 키 이벤트를 감지하는 리스너였다.

 

우선은 오류가 난 Enter 키 이벤트 리스너는 검색 기능에 부가적인 요소이기에 주석 처리를 해보고 다시 서치 해보았다. 

 

이벤트리스너에 대한 오류는 사라졌지만 검색을 해도 결과가 안나오는 문제는 여전했다.

( 콘솔 창에도 서치 부분에 대한 에러는 안뜬다. )

 

이후 여러가지 방법으로 여러가지 방법으로 2시간 정도 시도해보다가

끝내 해결하지 못해서 아예 검색 기능 로직을 바꾸기로 했다.

 

 

// 검색 기능을 위한 함수
function searchMovies() {
  const searchInput = document.getElementById("searchInput");
  const searchTerm = searchInput.value.trim().toLowerCase(); // 검색어 공백 제거 및 소문자로 변환

  // 검색어가 비어 있는 경우
  if (searchTerm === "") {
    alert("영화 제목을 입력해주세요.");
    return; // 검색어가 비어 있으면 더 이상 진행하지 않고 함수를 종료
  }

  // 검색어와 일치하는 영화만 필터링
  const filteredMovies = moviesData.filter(movie => movie.title.toLowerCase().includes(searchTerm));

  // 영화 목록 컨테이너를 비우고, 검색 결과만 표시
  const movieListContainer = document.getElementById("movieList");
  movieListContainer.innerHTML = "";

  if (filteredMovies.length > 0) {
    // 필터링된 영화 목록을 표시
    displayMovies(filteredMovies);
  } else {
    // 검색 결과가 없는 경우에 메시지를 표시
    const noResultsMessage = document.createElement("p");
    noResultsMessage.textContent = "검색 결과가 없습니다.";
    movieListContainer.appendChild(noResultsMessage);
  }
}

 

이건 내가 원래 짠 로직이다.

이건  searchMovies 함수 사용한 방법이다.

여기선 'moviesData' 배열을 활용해 검색을 수행했다.

입력된 검색어와 일치하는 영화를 'moviesData' 에서 필터링하고, 

그 결과를 화면에 표시하는 방법이다.

 

input 창에 입력한 값이 콘솔에는 잘 찍혔지만

const fiteredMovies 안에  'moviesData' 에 빈 배열이 들어왔고

끝내 해결하지 못하고 새로운 방법을 참고했다.

 

// 영화 데이터를 가져오는 .js 

const generateMovieCards = async () => {
  const movies = await fetchMovieData();

  const cardList = document.querySelector("#card-list");
  cardList.innerHTML = movies
    .map(
      movie => `
            <li class="movie-card" id=${movie.id}>
                <img src="https://image.tmdb.org/t/p/w500${movie.poster_path}" alt="${movie.title}">
                <h3 class="movie-title">${movie.title}</h3>
                <p>${movie.overview}</p>
                <p>Rating: ${movie.vote_average}</p>
            </li>`
    )
    .join("");

 

// 검색 기능. js

const handleSearch = searchKeyword => {
  const movieCards = document.querySelectorAll(".movie-card");

  movieCards.forEach(card => {
    const title = card.querySelector(".movie-title").textContent.toLowerCase();
    const searchedValue = searchKeyword.replace(/\s/g, "").toLowerCase();
    const titleWithoutSpaces = title.replace(/\s/g, "");

    if (titleWithoutSpaces.includes(searchedValue)) {
      card.style.display = "block";
    } else {
      card.style.display = "none";
    }
  });
};

 

새로운 방법은 handlerSearch 라는 이름의 함수다.

이 함수는 DOM 요소를 직접 조작하여 검색 결과를 화면에 표시하는 방법이다.

모든 'movie-card' 요소를 가져와서 각각의 제목을 검색어와 비교하여 화면에 나타내거나 숨기는 방법이다.

 

두 함수 모두 검색 로직을 수행하지만,

searchMovies 함수는 데이터를 기반으로 검색하고,

handleSearch 함수는 DOM을 직접 조작하여 검색 결과를 처리한다.

선택은 구현에 따라 다르며, API와 상호 작용하는 경우에는 searchMovies 방식이 더 일반적이라고 하고,

DOM 조작을 통한 검색 결과 처리는 이미 로딩된 데이터를 필터링하는 것이므로

일부 상황에서 더 효율적일 수 있다고 한다.

728x90