Dependency-free, google maps auto completion input. See Demos
install
npm install -S gplaces
or
bower install gplaces
usage
After importing the script, setting up your proxy, and setting gplaces.http
, you can simply add the attribute data-gplaces
to an HTML element that accepts input and can respond to keyup
events:
<input type="text" data-gplaces>
<!-- Or a textarea works just as well -->
<textarea data-gplaces></textarea>
Also, see browser support.
There are two main hurdles to getting this to work:
- Setting up your own proxy to Google's API (see why do I need a proxy?)
- Overriding gplaces http implementation to make a request to your api
Get Google API Access
Setup a project in the Google Developers Console: https://code.google.com/apis/console
After creating your project, find the Google Places API Web Service and enable it. Under the credentials section on the left, get an API key.
Setup your proxy
Since Google's Autocomplete API isn't very CORS-friendly, you'll need to setup a proxy on your own proxy. This is easy to do with node and express:
npm install -S gplaces
In your express app,
var express = require('express');
var app = express();
app.use( require('body-parser')() );
// Mount your api endpoint wherever you like
app.get( '/api/places-autocomplete'
, require('gplaces').proxy({
key: 'my-api-key'
})
);
app.listen( 3000, function( error ){
/* ... */
});
If you need help setting up a proxy for other platforms, create an issue and we'll help you out.
Implement gplaces.http
:
A feature of the gplaces library is the fact that the library will piggy-back off of your app's existing http interface to cut down on library size and errors.
Before making any requests, setup gplaces http method. Here's an example using superagent and browserify:
npm install -S superagent
var request = require('superagent');
var gplaces = require('gplaces');
gplaces.http( function( input, callback ){
request
.get('/api/places')
.query({ input: input })
.end( callback );
});
Here's an example using jquery:
gplaces.http( function( input, callback ){
$.getJSON( '/api/places?input=' + input )
.error( callback )
.success( callback.bind( null, null ) );
});
You can either use the HTML attribute api or the JavaScript API.
Adding the data-gplaces
attribute any html element that has a value and can respond to keyup events will automatically register the gplaces plugin.
<textarea data-gplaces></textarea>
Optional CSS selector that the autocomplete results will be rendered to:
<input type="text" data-gplaces data-target="#wrapper > .my-target">
...
<div id="wrapper">
<div class="my-target"></div>
</div>
A space-separated list of variants that will control look-and-feel of the autocomplete popover.
The JS api has more functionality than available from the markup.
The module exports a single function (the Gplaces Object Factory) with the following properties:
http( Function onRequest( input, callback ) )
Connect the gplaces api to your proxyproxy( [Object options] )
returns an express request handler
Gplaces Object Factory
The Gplaces Object Factory returns a Gplaces Object:
var gplaces = require('gplaces');
document.addEventListener('DOMContentLoaded', function(){
// The gplaces module exports a single function( Element el, Object options )
// Calling it on an element will register the gplaces plugin
// to that particular element
var autocompleter = gplaces(
document.getElementById('my-gplaces-input')
);
});
The element the plugin is registered to (The first arg to the factory)
The options passed to the Object Factory
The underlying input model which has the following interface:
- val([String value]) - gets or sets current value
- makeRequest([Function callback(error, result)]) - makes request to api
A model describing the current position of keyboard selection. Has the following members:
int length: 0
length of listint pos: -1
position in listup()
decrements posdown()
increments posset(pos)
sets pos
The element referring to the popover that contains our autocomplete results
Renders the current state of the plugin given an optional result from the autocomplete api.
Renders the current state of .selectionPosition
Sets the value of the input element based on the current state .model
Whether or not the popover is showing
Hides the popover results
Shows the popover
Moves the input elements' cursor position to the end
gplaces.proxy(...)
is a function that will return an express request handler. You need this to setup your proxy. Be sure to pass in your api key:
app.get('/api/places'
, require('gplaces').proxy({
key: 'my-api-key'
})
);
Gplaces relies on dependency injection to perform HTTP requests. The reason being that we did not want ot solve cross-browser HTTP requests and most apps will likely already have their own solution.
If you have not implement an http callback, then gplaces will throw an error if you attempt to get autocomplete results.
require('gplaces').http( function( input, callback ){
$.getJSON( '/api/places?input=' + input )
.error( callback )
.success( callback.bind( null, null ) );
});
IE8+ (IE8 with polyfills) and all major browsers
- https://cdnjs.cloudflare.com/ajax/libs/classlist/2014.01.31/classList.min.js
- https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.1.1/es5-shim.js
- https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.1.1/es5-sham.js
- http://storage.j0.hn/events-polyfill.js
If you perform an HTTP request to another domain see CORS, most browsers will ask the server to implement the Acccess-Control-Allow-Origin
response header. If the server does not implement the header, then browser will not allow the request.
Google does not implement this header. You will need to setup a proxy that does not violate Cross Origin Resource Policies.
Performing HTTP requests correctly from all browsers is quite frankly out-of-scope of this project. Virtually every project I work includes at least 1 one wrapper for XMLHTTPRequest and XDomain.
Simply hooking into that made for a smaller library making fewer assumptions and inevitably working in more places.
You're likely using them already. Why double implement wrappers for poor browsers?