I need to create typeahead service for cities and so on.
At the same time I need to use a typeahead directive (ng2-bootstrap), so I just need an array of strings which I'll be given by my service.
I decided to use google maps for that.
This code was taken from an example of google maps api
function initAutocomplete() {
// Create the autocomplete object, restricting the search to geographical
// location types.
autocomplete = new google.maps.places.Autocomplete(
/** #type {!HTMLInputElement} */(document.getElementById('autocomplete')),
{types: ['geocode']});
// When the user selects an address from the dropdown, populate the address
// fields in the form.
autocomplete.addListener('place_changed', fillInAddress);
}
I need to use it with Angular2... how can I do that? And is it possible?
Thank you in advance and good luck!
I would set an object from the callback associated with your event. Here is a sample:
autocomplete.addListener('place_changed', () => {
this.selectedPlace = autocomplete.getPlace();
});
and bind the form against this object
<form>
Name: <input [(ngModel)]="selectedPlace.name"/>
(...)
</form>
Edit
You need to reference an element to apply on using the ViewChild decorator:
<div #autocomplete></div>
and in the component:
#ViewChild('autocomplete')
autocompleteElt:ElementRef;
ngAfterViewInit() {
this.initAutocomplete();
}
initAutocomplete() {
this.autocomplete = new google.maps.places.Autocomplete(
this.autocompleteElt.nativeElement,
{types: ['geocode']});
(...)
}
Related
I'm looking to use Google Place Autocomplete on one of my Meteor App Input.
When I initialize a session, I have an InvalidValueError: not an instance of HTMLInputElement, but when I refresh the page one time, the autocomplete works well.
What do I need to change on my code in order to have autocomplete working on first session?
My code:
if (Meteor.isClient) {
window.onload = function() {
var autocomplete = new google.maps.places.Autocomplete(
(document.getElementById('autocomplete')),{types:['geocode']}
);
google.maps.event.addListener(autocomplete,'place_changed',function(){
var place = autocomplete.getPlace();
});
};
}
Thanks for your help.
Call below code on-focus of input element.
var autocomplete = new google.maps.places.Autocomplete(
(document.getElementById('autocomplete')),{types:['geocode']}
);
You should try using Template instance:
Template.autocomplete.onRendered(function() {
// Your autocomplete function
// var autocomplete = ...
});
My template name is "autocomplete" in this example.
I'm teasing google places API and I run into strange behavior at Autocomplete that I don't understand.
This is how I'm using it:
const AUTOCOMPLETE_OPTIONS = {
types: ['address'],
componentRestrictions: {
country: 'cz'
}
};
this.inputPlaceElement = $('#search-around-input')
this.inputPlaceSearchBox = new google.maps.places.Autocomplete(this.inputPlaceElement[0], AUTOCOMPLETE_OPTIONS);
google.maps.event.addListener(this.inputPlaceSearchBox,'places_changed', () => {
console.log('place change')
})
Autocomplete input is working as it should but place_changed is not triggered, I was trying some stuf with it, and the object that is returned from constructor is weird.
When I call methods getBounds() or getPlace() there are undefined
This is the object: I'm not sure what is wrong
The event triggered when a Place is selected is 'place_changed', while your sample uses 'places_changed'
Try:
google.maps.event.addListener(this.inputPlaceSearchBox,'place_changed', function() {
console.log('place change')
});
So I am trying to add the search bar of https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-addressform to my Meteor app.
First I needed to load the Google Places library. That link however also attempts to directly write to the DOM to grab another link. Meteor doesn't allow that so I decided to load the two js files like this.
Template.listingSubmit.rendered = function(){
if (!this.rendered){
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=places";
document.body.appendChild(script);
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://maps.gstatic.com/cat_js/maps-api-v3/api/js/17/13/%7Bmain,places%7D.js";
document.body.appendChild(script);
this.rendered = true;
}
};
Does that work?
My next question is how do I initialize the autocomplete text field?
The html in the corresponding template is simple.
<div id="locationField">
<input id="autocomplete" placeholder="Enter your address" type="text">
</div>
Now do I tried adding
var autocomplete = new google.maps.places.Autocomplete(
(document.getElementById('autocomplete')),{types: ['geocode'] }
);
to the Template.listingSubmit.rendered but nothing happens. I get a google not defined error. What went wrong?
I've been dealing with the same problem and just came across a solution. Here's what I did.
First, add the following package to your project with:
`mrt add googlemaps`
or, if you're using meteor >= 0.9:
meteor add mrt:googlemaps
Next, create the following file: /client/lib/googlePlaces.js
Place the following code inside this js file:
GoogleMaps.init({
'sensor': false, //optional
'key': 'your api key here!', //optional
'language': 'en', //optional
'libraries': 'places'
});
Obviously replace the api key with your key! This code will initiate the call to the google api and download the places script to the client.
Now, to answer your question about how to get the autocomplete to work. Your HTML and js look fine, except for one thing. You need to wrap your js in a window.onload function so that it will wait for the google api script to be downloaded!
HTML
<div id="locationField">
<input id="autocomplete" placeholder="Enter your address" type="text">
</div>
JS
window.onload = function() {
var autocomplete = new google.maps.places.Autocomplete(
(document.getElementById('autocomplete')),{types: ['geocode'] }
);
};
I haven't tested your HTML/JS but it looks very similar to mine.
Thought I'd share what finally worked for me
The package stays the same, but the js changed:
Template.myTemplateName.rendered = function () {
window.onload = function() {
input = document.getElementById('autocomplete');
autocomplete = new google.maps.places.Autocomplete(input);
// When the user selects an address from the dropdown,
google.maps.event.addListener(autocomplete, 'place_changed', function() {
// Get the place details from the autocomplete object.
var place = autocomplete.getPlace();
console.log("place: " + JSON.stringify(place) );
});
};
};
This is the solution that finally worked for me: I added the mrt:googlemaps package.
Then I setup the googlePlaces.js like so:
GoogleMaps.init({
'sensor': true, //optional
'key': '***my api key***', //optional
'language': 'en', //optional
'libraries': 'places'
});
Then I set up a variable for each input field that was going to use the autocomplete API, and set the template.render equal to that, like so:
var initAutoCompleteProfile = function() {
var autocomplete = new google.maps.places.Autocomplete(
(document.getElementById('autocomplete')),{types: ['geocode'] }
);
};
var initAutoCompletePost = function() {
var autocomplete = new google.maps.places.Autocomplete(
(document.getElementById('autocomplete')),{types: ['geocode'] }
);
};
Template.userUpdate.rendered = initAutoCompleteProfile;
Template.postSubmit.rendered = initAutoCompletePost;
The element ID was "autocomplete" for each element that was going to use it, but what really matters most is that you make a variable for each element that is going to use it for each template, and then set that template's rendered equal to that variable.
Question/Solution here:
Meteor Google Maps Autocomplete only works once on multiple templates
I am using google.maps.places.API to provide a location search to the user.
When the user types and selects a location, I am catching the location coordinates in a variable(center hidden element) and using it for processing. However when the user is not satisfied, they may want to blank out the location input element manually and try to search by other options. In this case I want to clear of the lat and lng variables location input and thus the center input element values. I have tried to capture the onBlur event of the location search box, but not able to clear these variables it.
<script>
var autocomplete;
function initialize() {
var input = (document.getElementById('location'));
var options = {
types: ['(cities)']
};
autocomplete = new google.maps.places.Autocomplete(input,options);
google.maps.event.addListener(autocomplete, 'place_changed', function() {
fillInAddress();
});
}
function fillInAddress() {
// Get the place details from the autocomplete object.
var place = autocomplete.getPlace();
var val = place.geometry.location;
document.getElementById('center').value = val;
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
Please advice how do I clear of the input element location( and thus element center ). Or am I missing a vital point in the code.
I've been looking at the example on:
http://code.google.com/apis/maps/documentation/javascript/examples/places-autocomplete.html
and have decided to incorporate it into my site.
Is it possible to limit the addresses to UK addresses only?
Try this:
var input = document.getElementById('searchTextField');
var options = {
types: ['(cities)'],
componentRestrictions: {country: 'tr'}//Turkey only
};
var autocomplete = new google.maps.places.Autocomplete(input,options);
You can't strictly/hard limit the locations that it finds, although there is a feature request in the system to do so, but you can set a 'bias' on the results. It's passed in as an argument to the autocomplete method as a google maps bounds object. Autocomplete will then favor locations within those boundaries. Note, however, that since this isn't a hard boundary, if there are matches for the search outside the boundaries it will return those.
From my usage it seems a bit buggy and can use some improvement - especially considering that anything outside your boundary is not tagged by proximity at all, so something one block outside the boundary is just as likely to show as something 1000 miles outside, so make sure you play around with getting the boundaries working right.
You can intercept the JSONP results that are returned by the google.maps.places.Autocomplete functionality and use them as you see fit, such as to limit by country and display the results.
Basically you redefine the appendChild method on the head element, and then monitor the javascript elements that the Google autocomplete code inserts into the DOM for JSONP. As javascript elements are added, you override the JSONP callbacks that Google defines in order to get access to the raw autocomplete data.
It's a bit of a hack, here goes (I'm using jQuery but it's not necessary for this hack to work):
//The head element, where the Google Autocomplete code will insert a tag
//for a javascript file.
var head = $('head')[0];
//The name of the method the Autocomplete code uses to insert the tag.
var method = 'appendChild';
//The method we will be overriding.
var originalMethod = head[method];
head[method] = function () {
if (arguments[0] && arguments[0].src && arguments[0].src.match(/GetPredictions/)) { //Check that the element is a javascript tag being inserted by Google.
var callbackMatchObject = (/callback=([^&]+)&|$/).exec(arguments[0].src); //Regex to extract the name of the callback method that the JSONP will call.
var searchTermMatchObject = (/\?1s([^&]+)&/).exec(arguments[0].src); //Regex to extract the search term that was entered by the user.
var searchTerm = unescape(searchTermMatchObject[1]);
if (callbackMatchObject && searchTermMatchObject) {
var names = callbackMatchObject[1].split('.'); //The JSONP callback method is in the form "abc.def" and each time has a different random name.
var originalCallback = names[0] && names[1] && window[names[0]] && window[names[0]][names[1]]; //Store the original callback method.
if (originalCallback) {
var newCallback = function () { //Define your own JSONP callback
if (arguments[0] && arguments[0][3]) {
var data = arguments[0][4]; //Your autocomplete results
//SUCCESS! - Limit results here and do something with them, such as displaying them in an autocomplete dropdown.
}
}
//Add copy all the attributes of the old callback function to the new callback function. This prevents the autocomplete functionality from throwing an error.
for (name in originalCallback) {
newCallback[name] = originalCallback[name];
}
window[names[0]][names[1]] = newCallback; //Override the JSONP callback
}
}
//Insert the element into the dom, regardless of whether it was being inserted by Google.
return originalMethod.apply(this, arguments);
};
James Alday is correct:
http://code.google.com/apis/maps/documentation/javascript/places.html#places_autocomplete
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(49.00, -13.00),
new google.maps.LatLng(60.00, 3.00));
var acOptions = {
bounds: defaultBounds,
types: ['geocode']
};
it is somewhat annoying as searching for Durham gives Durham, North Carolina as the second result, regardless of how you try to persuade it to region bias - you can set it to viewport map bounds and it'll still try to suggest NC state... The jQuery solution can be found here, but doesn't seem to give as many results as the v3 API.
http://code.google.com/p/geo-autocomplete/
The best way you would go about doing this, is to query the places api yourself and appending the queried string with your country. Or, of course, use the geo-autocomplete jQuery plugin.
Just change the google domain for the maps to your country domain and it will automatically search within your country only:
So:
http://maps.google.com/maps/api/geocode/xml?address={0}&sensor=false&language=en
To:
http://maps.google.nl/maps/api/geocode/xml?address={0}&sensor=false&language=nl
Try something like this.
// Change Bangalore, India to your cities boundary.
var bangaloreBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(12.864162, 77.438610),
new google.maps.LatLng(13.139807, 77.711895));
var autocomplete = new google.maps.places.Autocomplete(this, {
bounds: bangaloreBounds,
strictBounds: true,
});
autocomplete.addListener('place_changed', function () {
});
I find that if you set the map to roughly where you want then set bounds to it, the search finds places in that area first. You do not to physically show the map.
It works better than giving random overseas addresses first, setting to country does not work.
The code for autocomplete to get latln is:
<div id="map_canvas"></div>
<input type="text" name="location" id="location" placeholder="Type location...">
<input type="text" name="loc_latitude" id="latitude">
<input type="text" name="loc_longitude" id="longitude">
and the JS is:
$(document).ready(function () {
var mapOptions = {
center: new google.maps.LatLng(52.41041560, -1.5752999),
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map_canvas'),
mapOptions);
var autocomplete;
autocomplete = new google.maps.places.Autocomplete((document.getElementById(searchInput)), {
types: ['geocode'],
});
autocomplete.bindTo('bounds', map);
google.maps.event.addListener(autocomplete, 'place_changed', function () {
var near_place = autocomplete.getPlace();
document.getElementById('latitude').value = near_place.geometry.location.lat();
document.getElementById('longitude').value = near_place.geometry.location.lng();
});
});
$(document).on('change', '#'+searchInput, function () {
document.getElementById('latitude').value = '';
document.getElementById('longitude').value = '';
});
Not exactly what you asked for but it works for me.