Issue
When I had my Google Maps API snippet:
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"></script>
in index.html
, I got the error:
Uncaught InvalidValueError: initMap is not a function
I want to keep all of my bower_component
, CSS, API, and script declarations in my index.html
file on my Yeoman-scaffolded AngularJS web app. The map I was actually trying to recreate would be on another route, let's call it route "afterlogin", just a basic map. I separated the js and the html html components into afterlogin.js
and afterlogin.html
There are a number of potential causes for this. One of which was presented here as a matter of adjusting the call to match the namespace, https://stackoverflow.com/a/34466824/1923016 . Would this require an angular service? If so, how would the service work into the initMap
function and its call in the Google maps api snippet?
One of the complications is the order. I'm new to web app dev, but from what I can tell the index.html
loads first, uses the url in the snippet to make the callback to the initMap
function which is not featured in <script>...</script>
in the index.html
file nor in the app.js
file. Instead, since the init function is in a route's js code, it cannot be seen, hence the need for some kind of "namespace" version of the call. This leads to a console error even from the login route, which is not even where the div
for the map is.
---- EDIT: ----
Also note that in this case, this did not do the trick:
window.initMap = function(){
//...
}
This also does not apply, as the function is never called: Uncaught InvalidValueError: initMap is not a function
-- -- -- -- -- --
afterlogin.js
angular.module('myappproject').controller('AfterloginCtrl', function ($scope) {
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 17,
center: {lat: -33.8666, lng: 151.1958}
});
var marker = new google.maps.Marker({
map: map,
// Define the place with a location, and a query string.
place: {
location: {lat: -33.8666, lng: 151.1958},
query: 'Google, Sydney, Australia'
},
// Attributions help users find your site again.
attribution: {
source: 'Google Maps JavaScript API',
webUrl: 'https://developers.google.com/maps/'
}
});
// Construct a new InfoWindow.
var infoWindow = new google.maps.InfoWindow({
content: 'Google Sydney'
});
// Opens the InfoWindow when marker is clicked.
marker.addListener('click', function() {
infoWindow.open(map, marker);
});
}
});
afterlogin.html
<!DOCTYPE html>
<html>
<head>
<title>after login page</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
</body>
</html>
Solution
Since the Google Maps SDK script load a synchronic (due the async
attribute), there is the callback
parameter in the URL.
To solve the problem, you need to understand the async
mechanism in google sdk
The async attribute lets the browser render the rest of your website while the Maps JavaScript API loads. When the API is ready, it will call the function specified using the callback parameter.
https://developers.google.com/maps/documentation/javascript/tutorial#Loading_the_Maps_API
So the solution is to load the script synchronic:
In the script tag that loads the Maps JavaScript API, it is possible to omit the async attribute and the callback parameter. This will cause the loading of the API to block until the API is downloaded.
This will probably slow your page load. But it means you can write subsequent script tags assuming that the API is already loaded.
https://developers.google.com/maps/documentation/javascript/tutorial#sync
- You can remove the
async
attribute that way, the page will stop running until the script will complete downloaded and run on the page. So, when the browser will get to your code, all the SDK object will be available. - Now, since there is not code that calls to the
initMap
function (remember: who called it, it was the sdk script which call it only in theasync
mode), you need to call it by yourself. So, just call it in the end of the controller.
Answered By - Mosh Feu
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.