DEV Community

Cover image for How I did a Search filter for a city or state with Ajax
Raquel Santos | RS-coding
Raquel Santos | RS-coding

Posted on

How I did a Search filter for a city or state with Ajax

Hi everyone 👋 ,
today I will explain my solution for another challenge made by Wes Bos - "JavaScript 30".
This challenge was interesting to do because I did a review on important matters such as Ajax, promises, fetch, regex, array methods and string methods, spread operator.

Let's start!

HTML

1.HTML file is simple with a form tag that contains an input inside that is the search engine and a list that is the given suggestions based on the search.

Done that and the CSS style (you can check on my GitHub repository at the end of the article), let's start with JavaScript :

JS part1

2.First of all what I did was to assign the external data URL in a variable called endpoint.

3.I created another variable called cities that takes as value an empty array.

4.I created also a variable called prom( promise) to fetch the data that comes from an external source and push the items of that data into an empty array - cities constant .
To do that I used spread operator because if I didn't it would push a nested array inside the empty array and we needed every item to go to the empty array.

Note about spread operator:

The spread operator allows an expression to be expanded in places where multiple arguments (for function calls) or multiple elements (for array literals) are expected.

For function calls:

f(...iterableObj);
Enter fullscreen mode Exit fullscreen mode

For array literals:

[...iterableObj, 4, 5, 6]
Enter fullscreen mode Exit fullscreen mode

For destructuring:

[a, b, ...iterableObj] = [1, 2, 3, 4, 5];
Enter fullscreen mode Exit fullscreen mode

JS part2

5.I created a function that is responsible to find the city or state that matches what was searched.
This function takes two arguments, one is the word to match and the second is the cities array.
Inside the function, I used an array method - Filter - that returns an array filtered.
Inside that, I used the match() method

match() method returns a match between a string with regular expression.
Because the value of a regular expression is always different we need to build a regular Expression from a variable. So I used the RegExp constructor with a string parameter - wordToMatch

const regex = new RegExp( wordToMatch, 'gi')
Enter fullscreen mode Exit fullscreen mode

g - is for global search. Meaning it'll match all occurrences.
i - stands for ignoring case in the given string. Usually referred to as case-insensitive as pointed out in the comment.

Then I used that variable as an argument inside the match method for the city and also for the state

return place.city.match(regex) || place.state.match(regex)
Enter fullscreen mode Exit fullscreen mode

This function will return a small array with the matches city or states of what we searched.

JS part3

6.I accessed the input elements 'search' and ul 'suggestions' via DOM and add an event listener to 'search' input with change event and other with keyup event and a function called displayMatches that I have created after.

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

The displayMatches function first takes the result of the findMatches function and assigns it to a variable called matchArray.

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

After that, I created another variable called HTML that will be responsible to create an HTML of the result of the new array filtered.
First, the HTML variable gets the variable matchArray and does a map ( array method -The map() method creates a new array with the results of calling a function for every array element.)
to create a li tag with two span tags one for the city and the state and the other for the population.

const html = matchArray.map(place =>{
  return `<li>
             <span class="name"> ${place.city}, ${place.state}</span>
             <span class="population">${place.population}</span>
          </li>
         `
}
Enter fullscreen mode Exit fullscreen mode

After that, we get the innerHTML suggestion variable that represents the ul and assigns the HTML variable.

suggestions.innerHTML = html
Enter fullscreen mode Exit fullscreen mode

At this moment we can see already the results after we type something in the search.

JS part4

7.After that, all that was left was to do the part of colouring the background of the letters that matches what's written in search and putting a comma in the population number of 3 in 3 numbers.

Inside the displayMatches Function, inside the map and before returning I created a variable called regex that will create a regex constructor of the input actual value.

const regex = new RegExp(this.value, 'gi')
Enter fullscreen mode Exit fullscreen mode

then I created two variables, one for the city other for the state that replaces the individual element of property city and state from cities array and replaces whatever it matches in regex and replace it with a span class name 'hl'(highlight) and the value that the person searched for.

const cityName = place.city.replace(regex, `<span class="hl">${this.value}</span>`)
Enter fullscreen mode Exit fullscreen mode

The replace() method returns a new string with some or all matches of a pattern replaced by a replacement

Then we can replace place.city and place.state inside the literal template with cityName and stateName variables.

return `
       <li>
           <span class="name">${cityName},${cityState}</span>
           <span class="population">${place.population}</span>
       </li>
      `
Enter fullscreen mode Exit fullscreen mode

JSpart5

8.Finally I created a function that is responsible to put commas in the population number.

function numberWithCommas(x) {
   return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}
Enter fullscreen mode Exit fullscreen mode
return `<li>
            <span class="name">${cityName}, ${stateName}</span>
            <span class="population">${numberWithCommas(place.population)}</span>
        </li>
       `
Enter fullscreen mode Exit fullscreen mode

You can check the full code here and see the demo here

Discussion (0)