11<!DOCTYPE html>
22< html lang ="en ">
3+
34< head >
45 < meta charset ="UTF-8 ">
56 < title > Type Ahead 👀</ title >
67 < link rel ="stylesheet " href ="style.css ">
78</ head >
9+
810< body >
911
1012 < form class ="search-form ">
1416 < li > or a state</ li >
1517 </ ul >
1618 </ form >
17- < script >
18- const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json' ;
19+ < script >
20+ const debounce = ( fn , ms = 0 ) => {
21+ let timeoutId ;
22+ return function ( ...args ) {
23+ clearTimeout ( timeoutId ) ;
24+ timeoutId = setTimeout ( ( ) => fn . apply ( this , args ) , ms ) ;
25+ } ;
26+ } ;
27+
28+ const endpoint =
29+ 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json' ;
30+
31+ const dataArr = [ ]
32+
33+ fetch ( endpoint )
34+ . then ( blob => blob . json ( ) )
35+ . then ( data => dataArr . push ( ...data ) )
36+
37+ function findMatches ( itemToMatch , data , props ) {
38+ if ( ! itemToMatch ) {
39+ console . log ( 'empty' )
40+ return [ ]
41+ }
42+ const matches = [ ]
43+ if ( props ) {
44+ props = typeof props === 'string' ? [ props ] : props
45+ } else {
46+ props = Object . keys ( data [ 0 ] )
47+ }
48+ props . forEach ( prop => {
49+ const filtered = data . filter ( item => {
50+ const regex = new RegExp ( itemToMatch , 'gi' )
51+ return item [ prop ] . toString ( ) . match ( regex )
52+ } )
53+ matches . push (
54+ ...filtered
55+ )
56+ } )
57+ return matches
58+ }
1959
20- </ script >
60+ function numberWithCommas ( x ) {
61+ return x . toString ( ) . replace ( / \B (? = ( \d { 3 } ) + (? ! \d ) ) / g, ',' ) ;
62+ }
63+
64+ function displayMatches ( e ) {
65+ const matchArray = findMatches ( e . target . value , dataArr )
66+ let html
67+ if ( ! matchArray . length ) {
68+ html = `
69+ <li>Filter for a city</li>
70+ <li>or a state</li>
71+ `
72+ } else if ( matchArray . length ) {
73+ html = matchArray . map ( matchedItem => {
74+ const regex = RegExp ( e . target . value , 'gi' )
75+ const cityName = matchedItem . city . replace ( regex , `<span class="hl">${ e . target . value } </span>` )
76+ const stateName = matchedItem . state . replace ( regex , `<span class="hl">${ e . target . value } </span>` )
77+ return `
78+ <li>
79+ <span class="name">${ cityName } , ${ stateName } </span>
80+ <span class="population">${ numberWithCommas ( matchedItem . population ) } </span>
81+ </li>
82+ `
83+
84+ } ) . join ( '' )
85+ }
86+ suggestions . innerHTML = html
87+ }
88+
89+ const inputSearch = document . querySelector ( '.search' )
90+ const suggestions = document . querySelector ( '.suggestions' )
91+
92+ inputSearch . addEventListener ( 'change' , displayMatches )
93+ inputSearch . addEventListener ( 'keyup' , debounce ( ( e ) => {
94+ displayMatches ( e )
95+ } , 300 ) )
96+ </ script >
2197</ body >
22- </ html >
98+
99+ </ html >
0 commit comments