Skip to content

Example: Typeahead

yurtesen edited this page Aug 18, 2016 · 2 revisions

Here are some code examples on how typeahead code may function. In the examples the description and code lines are shown. However full results may be omitted to conserve space. It is up to the programmer to test and repeat the examples to see the full results.

Notice: Please see the Scopes wiki page for more detailed information about scopes and help about some problems you may face. (eg. 'is ambiguous' sql error)

Typeahead

Typeahed is not a typewriter feature! It is guessing of location info and showing possible results while user is typing.

1. Totally unknown user:

Lets assume that we know nothing about a users who enters their location to system. The user is from Turku, Finland. He will start typing with 'T', then 'u', then 'r'....

Strategy

  • We will look for all reasonably large cities using the city() scope of GeonamesGeonames.
  • We will look for the region of the city using admin1() scope of GeonamesGeonames.
  • The results should be ordered descending by population. Since higher the population, higher the chance of user being from that location. However if your site is very busy, you may want to skip the sorting since it is resource intensive.
  • We will limit the results to 5 results per query.
  • We will assume the user started with correct letter. It makes little sense to search for %string%, and most of the time more efficient to use string% instead.
  • We will show a list which has city,region,country code. eg. Turku, Southwest Finland, FI

Code

I tested this and the town Turku is in the list when first 3 letters are entered, when search string is 'Tur%'.

>>> GeonamesGeoname::City('Tur%')->select('geonames_geonames.geoname_id',
                                          'geonames_geonames.name',
                                          'geonames_geonames.country_code')
                                 ->admin1()->orderBy('population','desc')->limit(5)->get();
=> Illuminate\Database\Eloquent\Collection {#3336
     all: [
       ...,
       Yurtesen\Geonames\Models\GeonamesGeoname {#3330
         geoname_id: 633679,
         name: "Turku",
         country_code: "FI",
         admin1_geoname_id: 830708,
         admin1_name: "Southwest Finland",
       },
     ],
   }
>>>

2. We know the country of the user:

Method 1

Assume the user in example 1 but now we know the country of the user. We could give more relevant results by filtering cities by country. This is especially beneficial for first 3 characters. If city is not found after 3rd character, it is more likely that this is a city which is not in the country we are looking for.

Now we are able to find the location based on first character only!

>>> GeonamesGeoname::City('T%')->select('geonames_geonames.geoname_id','geonames_geonames.name','geonames_geonames.country_code')->admin1()->orderBy('population','desc')->limit(5)->where('geonames_geonames.country_code','FI')->get();
=> Illuminate\Database\Eloquent\Collection {#887
     all: [
       ...
       Yurtesen\Geonames\Models\GeonamesGeoname {#885
         geoname_id: 633679,
         name: "Turku",
         country_code: "FI",
         admin1_geoname_id: 830708,
         admin1_name: "Southwest Finland",
       },
       ...
     ],
   }
>>>

Method 2

Certain typeahead codes support prefetching. For example twitter-typeahed.js. We can prefetch all cities/towns in the country to begin with. For example in Finland this returns 362 names

>>> GeonamesGeoname::city()->where('country_code','FI')->count();
=> 362
>>>

If the location is not found with reasonable number of characters, then we can consult database again. But while reducing number of database queries greatly in most cases.