JavaScript-30-Day-6
Tags: javascript, css, html, webdev
Published: 2021-06-06 16:34:55

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d31szrttykxluik4b0ls.png)

**[click for project demo](https://cenacrharsh.github.io/JS-30-DAY-6/)**

On DAY-6 we made a **Type Ahead** feature where we've got a list of names of cities and states with their population in it. When we type something into the box, it's going to show all matching results containing that word and the words will also be highlighted.

This lesson was really very interesting and I would definitely like to use this in my future projects. I learned a lot of new things so let's dive right into it.

## Lessons Learned

- First and foremost the data containing the city and state names along with their population would be coming from an external source - a **cities.json** which Wes obtained from github.

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

So what we would be doing in this project is first we are going to fetch that data and then whenever someone types something we'll filter the array down to a subset of all the ones in which either the city/state names match.

First of all we'll need an empty array to put our data in
```javascript
const cities = [];
```
Now we need to fetch our data for which we would be using `fetch` **API**.

[MDN](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) says:

>The Fetch API provides an interface for fetching resources (including across the network). It will seem familiar to anyone who has used XMLHttpRequest, but the new API provides a more powerful and flexible feature set.

>The fetch() method takes one mandatory argument, the path to the resource you want to fetch. It returns a Promise that resolves to the Response to that request — as soon as the server responds with headers — even if the server response is an HTTP error status.

In simple terms Wes mentioned that the data that comes back from our fetch, it doesn't know what kind of data it is just yet. Also since we know it's JSON a simple `JSON.parse()` wouldn't work.

So to convert the raw data into JSON we can see in the console the promise that is returned by `fetch()` contains a function `.json()` but this also doesn't do the full work as it also returns a promise and after resolving it we finally get our data.

Another challenge is since our empty array is `const` we can't simply put data into it. We could although simply change it to `let` but it's always better to use `const`. Wes showed at this point that a `.push()` into the array would result in a nested array that is our main array will have only one element which would be the array containing our data. He also showed that if we simply add integers like `[2,3,4]` into our exiting array they are simply added into the array and are not nested. So using this logic and to put elements into the array as individual elements we use Array **spread** operator.

```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));

```

- Next thing we'll do is when someone types into the box we'll run a function that will take this massive array & filter it down into a subset where we can then listen to it.

To find the word matches we create a `findMatches()` function. Here the challenge is that inside the `.match()` function we can't use variables and whatever people search for will be variable and for that we need to use `RegExp` and then feed the result of the regular expression to `.match()`.

```javascript
function findMatches(wordToMatch, cities) {
  return cities.filter((place) => {
    // here we need to figure out if the city or state matches what was searched
    const regex = new RegExp(wordToMatch, "gi");
    return place.city.match(regex) || place.state.match(regex);
  });
}
```
Here the flags in `RegExp` used are **gi** where **g** is for glob al (look through entire string to match) and **i** for case-insensitive.

Now that we have found the matches we'll proceed to add the event listeners.

First we'll add a `change` event listener to the box. But the `change` event fires off only when you go off the input field, not  whenever you type into and key up so to fire off an event on key up as well we'll another event listener `keyup`.

```javascript
const searchInput = document.querySelector(".search");
searchInput.addEventListener("change", displayMatches);
searchInput.addEventListener("keyup", displayMatches);
```

The whole displayed content on screen would be handles inside the `displayMatches` function.

Inside this function `this.value` contains whatever the user has typed into the box and so we pass this to our `findMatches()` function.
```javascript
const matchArray = findMatches(this.value, cities);
```

We'll use the content in the variable matchArray to generate the html content for our page. Here to make things pretty we would also highlight the text that has matched so for that we'll create another `RegExp` and then use `replace()` which is going to find whatever is matched in the regx and replace it with a span having class of **hl** that is highlight. Here are the contents of **hl** class
```css
.hl {
  background: #ffc600;
}
```
and here is the complete **displayMatches()** function

```javascript
function displayMatches() {
  const matchArray = findMatches(this.value, cities);

  const html = matchArray
    .map((place) => {
      const regx = new RegExp(this.value, "gi");
      const cityName = place.city.replace(
        regx,
        `<span class="hl">${this.value}</span>`
      );
      const stateName = place.state.replace(
        regx,
        `<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;
}
```

Finally to beautify things Wes used a function to add commas in the population.

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

and with this our project for the day was completed.

GitHub repo:
{% github cenacrharsh/JS-30-DAY-6 no-readme %}

###Blog on Day-5 of javascript30
{% link https://dev.to/cenacr007_harsh/javascript-30-day-5-dl2 %}

###Blog on Day-4 of javascript30
{% link https://dev.to/cenacr007_harsh/javascript-30-day-4-13k0 %}

###Blog on Day-3 of javascript30
{% link https://dev.to/cenacr007_harsh/javascript-30-day-3-29o6 %}

[Follow me on Twitter](https://twitter.com/cenacr007_harsh)
[Follow me on Linkedin](https://www.linkedin.com/in/kumarharsh22/)

**DEV Profile**

{% user cenacr007_harsh %}

You can also do the challenge at [javascript30](https://javascript30.com/)

Thanks [WesBos](https://github.com/wesbos) to share this with us! 😊💖

**Please comment and let me know your views**
##Thank You!