๐Ÿ“–Day 6 - Ajax Type Ahead

JavaScript 30์˜ Day 6 ํ”„๋กœ์ ํŠธ๋Š” Fetch API์™€ ์ •๊ทœํ‘œํ˜„์‹์„ ์ด์šฉํ•ด ๊ฒ€์ƒ‰์ฐฝ์— ๋ฌธ์ž๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ํ•ด๋‹น ๋ฌธ์ž๊ฐ€ ํฌํ•จ๋œ ๋„์‹œ๋ฅผ ๋‚˜์—ดํ•˜๋Š” ํ”„๋กœ์ ํŠธ์ด๋‹ค.

๐Ÿค“๐Ÿ“„์ฝ”๋“œ ๋ชจ์•„๋ณด๊ธฐ

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Type Ahead ๐Ÿ‘€</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <form class="search-form">
      <input type="text" class="search" placeholder="City or State" />
      <ul class="suggestions">
        <li>Filter for a city</li>
        <li>or a state</li>
      </ul>
    </form>
    <script src="main.js"></script>
  </body>
</html>

CSS

html {
  box-sizing: border-box;
  background: linear-gradient(
    90deg,
    #98ddca 0%,
    #d5ecc2 33%,
    #ffd3b4 66%,
    #ffaaa7 100%
  );
  font-family: "helvetica neue";
  font-size: 20px;
  font-weight: 200;
}

*,
*:before,
*:after {
  box-sizing: inherit;
}

input {
  width: 100%;
  padding: 20px;
}

.search-form {
  max-width: 400px;
  margin: 50px auto;
}

input.search {
  margin: 0;
  text-align: center;
  outline: 0;
  border: 10px solid #f7f7f7;
  width: 120%;
  left: -10%;
  position: relative;
  top: 10px;
  z-index: 2;
  border-radius: 5px;
  font-size: 40px;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.12), inset 0 0 2px rgba(0, 0, 0, 0.19);
}

.suggestions {
  margin: 0;
  padding: 0;
  position: relative;
  /*perspective: 20px;*/
}

.suggestions li {
  background: white;
  list-style: none;
  border-bottom: 1px solid #d8d8d8;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.14);
  margin: 0;
  padding: 20px;
  transition: background 0.2s;
  display: flex;
  justify-content: space-between;
  text-transform: capitalize;
}

.suggestions li:nth-child(even) {
  transform: perspective(100px) rotateX(3deg) translateY(2px) scale(1.001);
  background: linear-gradient(to bottom, #ffffff 0%, #efefef 100%);
}

.suggestions li:nth-child(odd) {
  transform: perspective(100px) rotateX(-3deg) translateY(3px);
  background: linear-gradient(to top, #ffffff 0%, #efefef 100%);
}

span.population {
  font-size: 15px;
}

.hl {
  background: #87aaaa;
}

JavaScript

const endpoint =
  "https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json";

const cities = [];

fetch(endpoint)
  .then((blob) => blob.json())
  .then((data) => cities.push(...data));

function findMatches(wordToMatch, cities) {
  return cities.filter((place) => {
    const regex = new RegExp(wordToMatch, "gi");
    // gi means global insensitive
    return place.city.match(regex) || place.state.match(regex);
  });
}

function numberWithCommas(x) {
  return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

function displayMatches() {
  const matchArray = findMatches(this.value, cities);
  const html = matchArray
    .map((place) => {
      const regex = new RegExp(this.value, "gi");
      const cityName = place.city.replace(
        regex,
        `<span class="hl">${this.value}</span>`
      );
      const stateName = place.state.replace(
        regex,
        `<span class="hl">${this.value}</span>`
      );
      return `
      <li>
        <span class="name">${cityName}, ${stateName}</span>
        <span class="population">${numberWithCommas(place.population)}</span>
      </li>
    `;
    })
    .join("");
  suggestions.innerHTML = html;
}

const searchInput = document.querySelector(".search");
const suggestions = document.querySelector(".suggestions");

searchInput.addEventListener("change", displayMatches);
searchInput.addEventListener("keyup", displayMatches);

๐Ÿ”Ž์ฝ”๋“œ ์„ค๋ช…

  1. ๊ฐ€์žฅ ๋จผ์ € fetch()๋ฅผ ํ†ตํ•ด endpoint๋กœ๋ถ€ํ„ฐ ์‘๋‹ต์„ JSON ํ˜•ํƒœ๋กœ ํŒŒ์‹ฑํ•˜๊ณ  ๊ทธ๋ ‡๊ฒŒ ์–ป์€ ๋ฐ์ดํ„ฐ๋ฅผ cities์— Spread Operator๋ฅผ ์‚ฌ์šฉํ•ด push ํ•ด์ค€๋‹ค.

  2. ๋‹ค์Œ์œผ๋กœ๋Š” findMatches()ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด cities ๋ฐฐ์—ด์— Day 4์—์„œ ์ด์šฉํ–ˆ๋˜ filter ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•œ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋‹จ์–ด์ธ wordToMatch์™€ ๋น„๊ตํ•˜์—ฌ ๊ทธ ๋‹จ์–ด๊ฐ€ city๋‚˜ state์— ํฌํ•จ๋œ ๊ฒฝ์šฐ๋งŒ ํ•„ํ„ฐ๋งํ•ด์ค€๋‹ค. ์—ฌ๊ธฐ์—์„œ ์ •๊ทœ ํ‘œํ˜„์‹์ด ์‚ฌ์šฉ๋œ๋‹ค.

  3. ์ด์ œ searchํด๋ž˜์Šค์˜ input์ด ๋ฐ”๋€” ๋•Œ ๋งˆ๋‹ค ๋„์‹œ๊ฐ€ ๋‹ฌ๋ผ์ ธ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— change์™€ keyup ๋™์ž‘์— addEventListener๋ฅผ ์„ค์ •ํ•œ๋‹ค. ์‹คํ–‰ํ•  ํ•จ์ˆ˜๋กœ๋Š” displayMatches๋กœ findMatches(this.value, cities)์—์„œ input๊ณผ ์ผ์น˜ํ•˜๋Š” ๋„์‹œ array๋ฅผ matchArray์— ํ• ๋‹นํ•œ๋‹ค. ์ดํ›„์— map ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•˜๋Š”๋ฐ ๋งค์น˜๋˜๋Š” ๋‹จ์–ด๋ฅผ ํ•˜์ด๋ผ์ดํŠธ ์‹œ์ผœ์ฃผ๊ธฐ ์œ„ํ•ด์„œ replace๋ฅผ ์ด์šฉํ•ด hlํด๋ž˜์Šค๋ฅผ ๊ฐ€์ง„ ํƒœ๊ทธ๋กœ ๊ฐ์‹ธ์ค€๋‹ค.

fetch

: ๊ธฐ์กด์˜ ajax ํ†ต์‹ ์„ ์‚ฌ์šฉํ•  ๋•Œ XMLHttpRequest, jQuery.ajax()์™€ ๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. return type์€ Promise๊ฐ์ฒด์ด๋‹ค.

  let promise = fetch(url, [options])

options์— ์•„๋ฌด๊ฒƒ๋„ ๋„˜๊ธฐ์ง€ ์•Š์œผ๋ฉด ์š”์ฒญ์€ GET ๋ฉ”์„œ๋“œ๋กœ ์ง„ํ–‰๋˜๊ณ  url๋กœ๋ถ€ํ„ฐ ์ฝ˜ํ…์ธ ๊ฐ€ ๋‹ค์šด๋กœ๋“œ ๋œ๋‹ค.

promise

: JavaScript ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์— ์‚ฌ์šฉ๋˜๋Š” ๊ฐ์ฒด์ด๋‹ค. ์ฃผ๋กœ ์„œ๋ฒ„์—์„œ ๋ฐ›์•„์˜ค๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋™์ž‘์— ์ด์šฉํ•  ๋•Œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ž‘์—…์ด ๋๋‚˜๊ณ  ๋‚˜์„œ ๋™์ž‘ํ•ด์•ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ž‘์—…์ด ์ˆœ์ฐจ์ ์œผ๋กœ ์™„๋ฃŒ๋˜์–ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๊ฐ์ฒด๊ฐ€ promise์ด๋‹ค.
promise๊ฐ์ฒด๋Š” fetch ์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋‹ค์–‘ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

  • response.text() โ€“ ์‘๋‹ต์„ ์ฝ๊ณ  ํ…์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • response.json() โ€“ ์‘๋‹ต์„ JSON ํ˜•ํƒœ๋กœ ํŒŒ์‹ฑํ•œ๋‹ค.
  • response.blob() โ€“ ์‘๋‹ต์„ Blob(ํƒ€์ž…์ด ์žˆ๋Š” ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ) ํ˜•ํƒœ๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์ •๊ทœ ํ‘œํ˜„์‹ (RegExp ๊ฐ์ฒด)

: ์ •๊ทœ ํ‘œํ˜„์‹์€ ๋ฌธ์ž์—ด์— ๋‚˜ํƒ€๋‚˜๋Š” ํŠน์ • ๋ฌธ์ž ์กฐํ•ฉ๊ณผ ๋Œ€์‘์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ํŒจํ„ด์ด๋‹ค.
์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ ์šฐ๋ฆฌ๋Š” RegExp ๊ฐ์ฒด์˜ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด g์™€ i flag๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ g๋Š” ๋Œ€์ƒ ๋ฌธ์ž์—ด ๋‚ด์— ๋ชจ๋“  ํŒจํ„ด๋“ค์„ ๊ฒ€์ƒ‰ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๊ณ  i๋Š” ๋Œ€์ƒ ๋ฌธ์ž์—ด์— ๋Œ€ํ•ด์„œ ๋Œ€/์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

๐Ÿš€TIL(Today I Learned)

  • JavaScript์˜ ๋น„๋™๊ธฐ ํ†ต์‹ ์— ๋Œ€ํ•ด ๋” ์•Œ์•„๋ด์•ผ ํ•  ํ•„์š”์„ฑ์„ ๋Š๋‚„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.
  • fetch, promise(๊ฐ์ฒด), RegExp, addEventListener(change), addEventListener(keyup)

JavaScript 30 ํ”„๋กœ์ ํŠธ ๊ฒฐ๊ณผ๋ฌผ

'Language > JavaScript' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[JS] ๐Ÿ—“๏ธJavaScript 30 - Day 8  (0) 2021.11.22
[JS] ๐Ÿ—“๏ธJavaScript 30 - Day 7  (0) 2021.11.21
[JS] ๐Ÿ—“๏ธJavaScript 30 - Day 5  (0) 2021.11.18
[JS] ๐Ÿ—“๏ธJavaScript 30 - Day 4  (0) 2021.11.17
[JS] ๐Ÿ—“๏ธJavaScript 30 - Day 3  (0) 2021.11.12