Skip to content

Instantly share code, notes, and snippets.

@badsyntax
Last active November 14, 2022 22:54
Show Gist options
  • Save badsyntax/4330899 to your computer and use it in GitHub Desktop.
Save badsyntax/4330899 to your computer and use it in GitHub Desktop.
Googe places autocomplete implementation using Twitter bootstrap typeahead and google's autocomplete and geocoding services
/**
* Author: Richard Willis - badsyntax.co
* Example here: http://demos.badsyntax.co/places-search-bootstrap/example.html
*
* Please note: This is not a reliable method of geocoding the address. Using the
* PlacesService is a much better approach. View the example above for an example
* of using the PlacesService to geocode the address.
*/
var service = new google.maps.places.AutocompleteService();
var geocoder = new google.maps.Geocoder();
$(field).typeahead({
source: function(query, process) {
service.getPlacePredictions({ input: query }, function(predictions, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
process($.map(predictions, function(prediction) {
return prediction.description;
}));
}
});
},
updater: function (item) {
geocoder.geocode({ address: item }, function(results, status) {
if (status != google.maps.GeocoderStatus.OK) {
alert('Cannot find address');
return;
}
map.setCenter(results[0].geometry.location);
map.setZoom(12);
});
return item;
}
});
@saurabh-agrawal83
Copy link

Works great!..thanks for sharing..

@idrakimuhamad
Copy link

Thanks!

@lukashoffmann
Copy link

works great! thx!

@sivareddy-cc
Copy link

Its Working ... ! Thank you very much for the code

@badsyntax
Copy link
Author

Glad some people found this handy.

I've created a full working example here: http://demos.badsyntax.co/places-search-bootstrap/example.html

@sjaaksola
Copy link

Great Job Richard!

But this isn't working with bs 3, gives error: "Error: one of local, prefetch, or remote is required"

Can you help? :)

--- EDITED ---

I gave up :) im using now bootstrap 3 rc1 and google api, and some style modifications.. you cant see the difference :P

@ScotterC
Copy link

@badsyntax is there a repo for your jquery.places-search ?

@hakanb
Copy link

hakanb commented Aug 25, 2013

Thanks for this, @badsyntax. For anyone else dealing with missing results using this example, I found a small issue where valid results whose names do not contain the query are not displayed. For example, try searching for "mcdonald's nyc" in the demo and you will notice no results are returned, while the same search returns five results on Google's autocomplete example.

To fix this, override Typehead's default matcher function, which hides results whose names do not contain the query, by adding a matcher function to the $.typeahead's call like so:

matcher: function (item) {
    return true;
}

@badsyntax
Copy link
Author

@ScotterC I have not created a repo for this code. If you would like to do so, feel free to use my code.

To everyone else, I wanted to create a bootstrap 3 version, but I'm quite disappointed that Bootstrap 3 dropped the typeahead plugin.

I'm really grumpy about this, because the new "fancy" typeahead.js plugin is just another typical bloated jquery plugin and is NOT a drop-in replacement for bootstrap 2.3.0 typeahead.

Seriously, there's no API methods to build up the list of suggestions manually. The plugin expects a data source, and it expects to do all the filtering within a large data set. Whereas with the Google Places API, the API itself does all the filtering and just returns the suggestions. I can't combine the two. I can't manually add the list of suggestions. Such a fancy plugin, so very useless.

If you want to use the typeahead with google's autocomplete with Bootstrap 3, you will have to use Bootstrap 2.3.0 typeahead.

I willl update this gist if/when typeahead.js provides a simple API method for building the list of suggestions manually.

@toolsmith
Copy link

I completely agree...I've been trying to migrate my old bootstrap code using autocomplete and typeahead to 3.0 but it has been a nightmare! Has anyone else had any luck in doing so?

@svub
Copy link

svub commented Oct 7, 2013

Found a hack fpr the new typeahead so that suggestions can be provided using a callback method again.
It goes something like this:

(t = $("field")).typeahead({ local: [] });
t.data("ttView").datasets[0].getSuggestions = function(query, callback) {
  var suggestions = ... gather your suggestions here ...
  var data = [];
  for (suggestion in suggestions) { data.push(this._transformDatum(suggestion)); }
  callback(data)
}

More details at http://svenbuschbeck.net/wordpress/2013/10/callback-method-for-twitters-typeahead/
Guess this should allow you to use autocomplete again easily.

@ficshelf
Copy link

ficshelf commented Jan 9, 2014

this is great. many thanks!

I am however wrecking my brain trying to port your example to the latest twitter typeahead.js instead of the bootstrap 2 version. help?

@badsyntax
Copy link
Author

@ficshelf read the comments in this thread, it's not possible without hacks.

Copy link

ghost commented Apr 27, 2014

@svub Where do i need to put your code so that autocomplete would work again ? Can't find place where to put it.

@Azaret
Copy link

Azaret commented Dec 31, 2014

Just in case anyone get to this page in the future, as it's like second when googling typeahead with gmaps.

It's totally possible to make typeahead works with google maps easily without hacks :

var geocoder = new google.maps.Geocoder();

$('.typeahead').typeahead({
    autoselect: true,
    sections: [{
        name: 'google',
        minLength: 4,
        templates: {
            header: '<h5 class="typeahead-header">Google Results</h5>'
        },
        source: function (q, value) {
            geocoder.geocode({ address: q }, function (results, status) {

                value($.map(results, function (result) {
                    retval = [];
                    retval.push({ value: result.formatted_address });
                    return retval;
                }));
            });
        }
  }]
});

source : twitter/typeahead.js#220 (comment)

@ronnyandre
Copy link

Couldn't get that to work @Azaret .. No errors, typeahead is initialized, but no dropdown with results.

@vinicius33
Copy link

thx for sharing! :)

@tomhalley
Copy link

tomhalley commented Apr 24, 2017

@badsyntax You created a project for it on google developer console and assigned the demo an API key.... then you deleted the project. Probably best just not to have given it an API key in the first place

@safakz
Copy link

safakz commented Oct 24, 2017

I think it will be a little late to answer @ronnyandre :) But this would be better. And moreover if any map on page it would be fit bounds to selected suggestions geometry

var geocoder = new google.maps.Geocoder();
$('.typeahead').typeahead({
                                            autoselect: true,
                                                minLength: 4,
                                              },{
                                                name: 'google',
                                                displayKey: 'address',
                                                templates: {
                                                    header: '<h5 class="typeahead-header">Google Results</h5>'
                                                },
                                                source: function (q, sync, async){
                                                    geocoder.geocode({ address: q }, function (results, status) {
                                                      for (var i = results.length - 1; i >= 0; i--) {
                                                        async([{address:results[i].formatted_address, geometry:results[i].geometry}]);
                                                      }
                                                    });
                                                }
                                          }
                                        ).on('typeahead:selected', function (obj, datum) {
                                            if(datum)
                                            {
                                              var geometry = datum.geometry;
                                               map.fitBounds(geometry.bounds? geometry.bounds : geometry.viewport);
                                            }
                                        });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment