[JS] JavaScript30 챌린지 6일차 Ajax Type Ahead

Seju·2023년 7월 3일
2

JavaScript

목록 보기
15/28

Ajax Type Ahead

🚀 구현 목표


Ajax 비동기 통신 fetch를 이용해서 데이터를 받아와 화면에 출력 및 검색해보자!


⛷️ fetch를 통한 json 데이터서버와 통신하기


    const endpoint =
        "https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json";
  • 먼저 endpoint라는 변수에 할당된 json 데이터가 존재한다

endpoint json 데이터파일

  • 해당 변수를 담기 위하여 cities라는 빈배열을 선언하고 그 배열안데 json파일을 담아보자

    • const cities = [];
  • 해당 json 데이터서버와 통신하기 위해 fetch라는 메서드를 사용한다

여기서 fetch() 메서드란?
네트워크에서 리소스를 취득하는 절차를 시작하고, 응답이 사용 가능해지면 이행하는 프로미스를 반환한다 ➡️ promise는 요청에 대한 응답을 나타내는 Response 객체로 이행한다


endpoint를 fetch메서드를 사용했더니 promise 객체를 반환하는 모습

  • 그럼 반환한 promise객체는 어떻게 가공해야할까❓

⌛ .then 사용

promise로 반환한 객체에 대해 .then을 참조하면 해당 dataResponse객체를 확인해볼 수 있다

promise 객체로 가져온 endpoint json 데이터를 .then으로 1차 가공한 모습

  • 하지만 .then 사용만으로는 현재 데이터의 정보를 받아 올 수 없다

💫 JSON() 객체 파싱하기

JSON.parse()메서드는 JSON 문자열의 구문을 분석 후 ➡️ Javascript 값이나 객체를 생성한다


그럼 .then으로 1차 가공한 blob객체를 JSON.parse()로 파싱하면

에러가 나타나는 이유는 무엇일까

  • 해당 에러는 JSON.parse()메서드가 유효한 JSON 형식이 아닌 데이터를 파싱하려고 시도했기때문에 발생하는 에러이다.
  • 그래서 먼저 파싱한 blob 내의 json()객체에 접근 후 ➡️ .then으로 2차로 가공해야한다!

blob.json() 객체의 console.log


  • blob 객체를 json()객체로 파싱하고 ➡️ data라는 데이터에서 console.log를 찍어보면❓

이렇게 data 변수 내에 1000개의 json형식의 데이터타입이 담겨져 있는걸 볼 수 있다

🐚 빈 배열 cities에 파싱한 data 넣어보기

  • 빈배열 cities에 파싱한 datapush 해보자

🤔 하지만 이렇게 cities에 바로 data를 push해버리면 배열 안에 배열로 json 데이터들이 담겨지게 된다 이런 이유로 data를 spread 연산자를 사용해 전개해야한다

spread 연산자를 사용해서 전개한 모습

⛺ findMatch() 함수 만들기

function findMatches(wordToMatch, cities) {
  		// 여기서 우리는 주에 있는 도시가 검색된 것과 일치하는지 알아내야함
        return cities.filter((place) => 
          const regex = new RegExp(wordToMatch, "gi");
  			// place의 city 및 place.state 값이 검색와 일치하는지 확인
          return place.city.match(regex) || place.state.match(regex);
        });
      }
  • 먼저 findMatch() 함수에 매개변수로 wordToMatch:검색어cities:도시목록을 매개변수로 받는다
  • filter 함수로 cities 배열에서 새로운 배열을 생성한다
  • new RegExp로 정규 표현식을 생성하고
  • new RegExp에 매개변수로 검색어와, gi라는 매개변수를 전달한다
    • gi : 정규표현식에서 gi플래그대소문자를 구별하지 않겠다는 의미
  • 리턴값으로 match 함수를 사용하게 되는데, match란 ❓
    • match() : 문자열이 정규식과 매치되는 부분을 검색하는 메서드
  • place의 cityplace.state 값이 검색와 일치하는지 확인한다

findMatch() 함수에 전달인자로 'Bos'를 전달한 모습 city에 Bos라는 문자열이 포함되어있는 도시를 찾을 수 있다

🚤 displayMatches() 함수 만들기

  • querySelector로 html의 form과 input을 읽어온다

      const searchInput = document.querySelector(".search");
      const suggestions = document.querySelector(".suggestions");
  • 읽어온 input에 addEventListener로 change이벤트keyup이벤트가 일어났을 경우
    displayMatches함수가 실행될 수 있도록 핸들링 한다
    searchInput.addEventListener("change", displayMatches);
      searchInput.addEventListener("keyup", displayMatches);

displayMatch의 this.value는?

    function displayMatches() {
        console.log(this.value);
      }

해당 this.value는 곧 내가 input에서 입력한 값이 value로 displayMathch()함수에서 쓰여진다는 의미이다

  • 그럼 this.value를 이용해서 displayMatch() 함수에서 만들어둔 findMatch() 함수를 변수로 만들어 적용하면❓
      function displayMatches() {
        const matchArray = findMatches(this.value, cities);
        console.log(matchArray);
      }

this.value(내가 input에 입력한 값)을 전달인자로 findMatches()에 전달하면 내가 입력한 값이 변수로 할당되어 읽어올 수 있게된다!

  • 이제 만든 matchArray 변수를 이용해 element node를 생성해야 한다
  • html 변수를 만들어 matchArray의 배열에 대해 map()함수를 사용해 새로운 배열을 생성한다
const html = matchArray
          .map((place) => {
            return `
            <li>
              <span class="name">${place.city}, ${place.state}</span>
              <span class="population">${place.population}</span>
            </li>
          `;
          })
          .join("");

join()을 쓰는 이유?
join() : 배열의 모든 요소를 연결해 하나의 문자열로 만듬

map으로 만든 새배열 place에 join("")을 안쓰게 된다면
생성한 새로운 list의 끝에 ,가 붙어버려 보기 이상해진다..

  • 생성한 html 변수를 suggestion(ul태그) 내의 innerHTML로 붙인다
    • suggestions.innerHTML = html;

suggestion에 html를 넣고, value를 넣은 모습

this.value에 highlights 효과 넣어주기

  • displayMatches() 함수내부에 new RegExp에 매개변수로 this.value"gi"값을 넣어주고
  • cityName이라는 변수를 할당해 place의 city를 replace()한다

    replace() 메서드란?
    패턴에 일치하는 일부 또는 모든 부분이 교체된 새로운 문자열을 반환
    패턴 : 정규표현식

  const cityName = place.city.replace(regex, `<span class="hl">${this.value}</span>`);
  • 만든 cityName을 기존에 만들어 뒀던 ${place.city}부분을 ${cityName}로 교체한다

${place.city} ➡️ ${cityName}

this.value가(내가 input에 검색한 내용)이 하이라이팅되고 있는 모습

profile
Talk is cheap. Show me the code.

0개의 댓글