Reputation: 251
I know this is a really common error, but I read all the other "Uncaught ReferenceError: google is not defined" questions and none of them helped me fix it. I am using the Google Places API but my application does not use a map so I referred to this question to figure that out.
Many of the answers talked about loading the api script asyncronously before everything else, and the order of the scripts matters, but I don't think that's my issue. I followed the example in the Places API Documentation so I don't know what I am doing wrong.
Here is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
</head>
<body>
<h1>Places Near Chicago</h1>
<div id="list"></div>
<script src="https://maps.googleapis.com/maps/api/js?key=API_KEY&libraries=places" async defer></script>
<script>
var service = new google.maps.places.PlacesService(document.getElementById('list'));
var request = {
location: new google.maps.LatLng(41.8781136, -87.6297982),
radius: 5
};
service.search(request, callback);
function callback(results, status){
if(status == google.maps.places.PlacesServiceStatus.OK){
console.log(status);
for (var i = 0; i < results.length; i++) {
console.log(results[i].name, results[i].types);
}
}
};
</script>
</body>
</html>
The issue is specifically with the line
var service = new google.maps.places.PlacesService(document.getElementById('list'));
Thanks!
EDIT: I updated my code as per Jeff's suggestion and still get the same error.
Upvotes: 3
Views: 12818
Reputation: 6983
From my reading, async
and defer
aren't meant to be used at the same time.
While your <script>
that loads the API from google is deferred, your <script>
with your code is not deferred. (If you remove async
and defer
your code works, but is theoretically slower.)
If you defer your code execution until the document is loaded (and the google api instantiated), then your code should work.
i.e., as sideroxylon alluded to,
<script>
$(document).ready(function() {
var service = new google.maps.places.PlacesService(document.getElementById('list'));
...
})
</script>
or
<script>
document.addEventListener('DOMContentLoaded', function() {
var service = new google.maps.places.PlacesService(document.getElementById('list'));
...
})
</script>
...I can not get this to work with async
, but I can with defer
. async
can be run at any time, even after DOMContentLoaded
. According to this, defer
does preserve order.
Here's a good resource for execution order: https://www.kirupa.com/html5/running_your_code_at_the_right_time.htm
It shows that defer
happens just before the DOMContentLoaded
Event and async
scripts can execute at any time, although before the final load
Event.
As to why their example works, note that they add &callback=initMap
to the API URL, which presumably asks their code to call initMap()
after their code is initialized. That way you can chain your code (your initMap()
function) to their asynchronous load. e.g.,
<script>
// define your callback before you invoke the API.
function my_code() {
var service = new google.maps.places.PlacesService(document.getElementById('list'));
....
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=APIKEY&libraries=places&callback=my_code" defer async ></script>
Upvotes: 3