Using Google Places Autocomplete with Meteor - google-maps

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

Related

google.script.run to reload google chart in HTML-service page

Just like I would inject new html on a div using google.script.run on a page without reloading, I have spent countless hours trying to do the same but with a google-visualization pie chart, I want to call as many times as needed this google.run.script through a callback.
This is the button with multiple callbacks:
<button onclick="google.script.run.withSuccessHandler(refresh).report(user());">Generate report</button>
OK, this is what user do:
<script>
function user() {
var user = $("input[type=radio]:checked").val();
return user;
}
</script>
Report() simply returns a new array of data for a chart, it will change depending on user.
Finally this is my chart script.
<script>
google.load("visualization", "1", {packages:["corechart"], "callback": refresh});
google.setOnLoadCallback(refresh);
function refresh(e) {
var data = google.visualization.arrayToDataTable(e);
var options = {
title: 'Chart',
is3D: true,
pieSliceText: 'label',
};
var chart = new google.visualization.PieChart(document.getElementById('piechart_3d'));
chart.draw(data, options);
}
</script>
My script works as intended all the way, except the end where I can't get it to update the chart everytime I click the button. Which loads new array data for the chart. I have simplified the code just for this post.
I managed to make it work as intended by parsing the callback value with JSON.parse(e), very hidden for me to figure it out.

google maps api autocomplete works at localhost but does not work on the server

I used google maps api for autocomplete of places.
Everythings works in localhost, but when i publish and upload it on server, it doesn't work...Why it happen? the dropdown of places does not show.
Here is my HTML:
<input type="text" id="autocomplete">
Here is my JS:
<script src="https://maps.googleapis.com/maps/api/js?sensor=false&libraries=places"></script>
<script>
var autocomplete;
function initialize() {
autocomplete = new google.maps.places.Autocomplete(
(document.getElementById('autocomplete')), {
types: ['(cities)'],
componentRestrictions: { country: "ph" }
});
google.maps.event.addListener(autocomplete, 'place_changed', function () {
fillInAddress();
});
}
placeParser = function(place){
result = {};
for(var i = 0; i < place.address_components.length; i++){
ac = place.address_components[i];
result[ac.types[0]] = ac.long_name;
}
return result;
};
function fillInAddress() {
var place = autocomplete.getPlace();
document.getElementById("latitude").value = place.geometry.location.lat();
document.getElementById("longitude").value = place.geometry.location.lng();
components = placeParser(place);
}
initialize();
There are 3 issues
you are calling initialize without knowing if the maps-API already has been loaded, remove the call of initialize and use the callback-parameter of the maps-API instead
the maps-API now requires a key.
As it seems there are circumstances(undocumented) where it may work without a key(I guess for requests from localhost and from domains which have been used the maps-API before a key has been required), probably your domain doesn't match this criteria, so you should/must use a key
(Additionally)I would call it a bug by google:
As it seems, now the use of the Places-library requires that the Places API Web Service also has been activated for a project( before it was sufficient to activate only the Maps JavaScript API )

Meteor and Google Place Autocomplete - InvalidValueError: not an instance of HTMLInputElement

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.

limiting google maps autocomplete to UK address only

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.

Customize Google Maps info window?

I'm working on a website of a client, a local church. I've embedded a Google Map using the Link feature on the Maps page. The info window on the map includes "Reviews," and the church is concerned about this. Is there a way to remove that from the info window? I don't want to remove any reviews themselves, just that link on the info window?
Is this possible? Are there any other customization options (besides the size) one can manipulate via the query string?
Nearly 2 years ago, I created a custom map with complete control over the contents of the bubble, using the API and some code manipulation. Click on the above link for a demo. I've cleaned up the code for this answer, although to implement you'll need to replace all YOUR__BLANK__HERE text with the appropriate values.
Step 1: Call the gMaps API
<script src="http://maps.google.com/maps?file=api&v=2&key=YOUR_API_KEY_HERE"
type="text/javascript">
</script>
Step 2: In the body of your document, create an element with id "map". Size and position it with CSS. It requires a height and width.
<div id="map" class="content"></div>
Step 3: After the div has been defined in the DOM, it is safe to insert the following script tag:
<script type="text/javascript">
//<![CDATA[
// Check to see if this browser can run the Google API
if (GBrowserIsCompatible()) {
var gmarkers = [];
var htmls = [];
var to_htmls = [];
var from_htmls = [];
var i=0;
// A function to create the marker and set up the event window
function createMarker(point,name,html) {
var marker = new GMarker(point);
// The info window version with the "to here" form open
to_htmls[i] = html +
'<br />Start address:<form action="http://maps.google.com/maps" method="get">' +
'<input type="text" SIZE=40 MAXLENGTH=40 name="saddr" id="saddr" value="" /><br>' +
'<INPUT value="Get Directions" TYPE="SUBMIT">' +
'<input type="hidden" name="daddr" value="' + point.lat() + ',' + point.lng() +
// "(" + name + ")" +
'"/>';
// The inactive version of the direction info
html = html + '<br><a href="javascript:tohere('+i+')">Get Directions<'+'/a>';
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(html);
});
gmarkers[i] = marker;
htmls[i] = html;
i++;
return marker;
}
// functions that open the directions forms
function tohere(i) {
gmarkers[i].openInfoWindowHtml(to_htmls[i]);
}
// Display the map, with some controls and set the initial location
var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(
YOUR_LATITUDE_HERE,
YOUR_LONGITUDE_HERE
),
YOUR_ZOOM_LEVEL_HERE // a value of 13 worked for me
);
// Set up one marker with an info window
var marker = createMarker(
new GLatLng(
YOUR_LATITUDE_HERE,
YOUR_LONGITUDE_HERE
),
'YOUR_MARKER_NAME_HERE',
'<i>YOUR_HTML_HERE<'+'/i>');
/* repeat the process to add more markers
map.addOverlay(marker);
var marker = createMarker(
new GLatLng(
YOUR_LATITUDE_HERE,
YOUR_LONGITUDE_HERE
),
'YOUR_MARKER_NAME_HERE',
'<i>YOUR_HTML_HERE<'+'/i>');
map.addOverlay(marker);*/
}
// display a warning if the browser was not compatible
else {
alert("Sorry, the Google Maps API is not compatible with this browser");
}
// This Javascript is based on code provided by the
// Blackpool Community Church Javascript Team
// http://www.commchurch.freeserve.co.uk/
// http://www.econym.demon.co.uk/googlemaps/
//]]>
</script>
Using this code, the bubble contains the html you specify in YOUR_HTML_HERE plus a link to Get Directions, which (when clicked) turns into a textbox asking for a starting address. The result of the query, unfortunately, opens in a new browser window (since, at time of original publishing the API did not include directions capabilities)
I think I found the answer to my own question. The info window itself can't be modified, but by linking to the map for the address itself rather than the church as a business entity does the trick. The driving directions link is still there and that's mostly all they wanted.