DEV Community

Cover image for JavaScript-30-Day-6
KUMAR HARSH
KUMAR HARSH

Posted on • Updated on

JavaScript-30-Day-6

Alt Text

click for project demo

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.
const endpoint =
  "https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json";
Enter fullscreen mode Exit fullscreen mode

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

const cities = [];
Enter fullscreen mode Exit fullscreen mode

Now we need to fetch our data for which we would be using fetch API.

MDN 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.

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

Enter fullscreen mode Exit fullscreen mode
  • 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().

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);
  });
}
Enter fullscreen mode Exit fullscreen mode

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.

const searchInput = document.querySelector(".search");
searchInput.addEventListener("change", displayMatches);
searchInput.addEventListener("keyup", displayMatches);
Enter fullscreen mode Exit fullscreen mode

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.

const matchArray = findMatches(this.value, cities);
Enter fullscreen mode Exit fullscreen mode

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

.hl {
  background: #ffc600;
}
Enter fullscreen mode Exit fullscreen mode

and here is the complete displayMatches() function

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;
}
Enter fullscreen mode Exit fullscreen mode

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

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

and with this our project for the day was completed.

GitHub repo:

Blog on Day-5 of javascript30

Blog on Day-4 of javascript30

Blog on Day-3 of javascript30

Follow me on Twitter
Follow me on Linkedin

DEV Profile

You can also do the challenge at javascript30

Thanks WesBos to share this with us! 😊💖

Please comment and let me know your views

Thank You!

Top comments (2)

Collapse
 
rohitk570 profile image
ROHIT KUMAR

👌👌

Collapse
 
rash123 profile image
RASHMI VERMA

👍