jQuery executes before Google map loads: "map is undefined" - google-maps

Aside from jQuery and Google Maps, I have two scripts included in the head of my page:
<script src="js/map.js" type="text/javascript"></script>
<script src="js/site.js" type="text/javascript"></script>
map.js contains the code to initialize my map and also have the following function to place a marker on it:
function placeMarker(marker){
clearLocations();
var latlng = new google.maps.LatLng(
parseFloat(marker.lat),
parseFloat(marker.lng)
);
var marker = createMarker(latlng);
map.setZoom(14);
var latLng = marker.getPosition();
map.setCenter(latLng);
}
When I call placeMarker inside $(document).ready() in site.js, I get the error, 'map is undefined'. However when I call another function in site.js that executes when a button is clicked, placeMarker runs in its callback without a problem:
$.ajax({
url: 'ajax/json.php',
dataType: 'json',
data: 'search_string='+inpMapSearch+'&country='+Country,
success: function(data) {
console.log(data);
placeMarker(data);
}
});
Does this mean that the placeMarker function call inside $(document).ready() is trying to execute before the map is initialized? How can I run placeMarker after the map is initialized?
=== EDIT ===
As per request here is the code that initializes the map:
google.maps.event.addDomListener(window, 'load', load);
function load() {
map = new google.maps.Map(document.getElementById("map"), {
center: new google.maps.LatLng(18.735693,-70.162651),
zoom: 8,
mapTypeId: 'roadmap',
mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU}
});
}

Because the window load event fires after the document.ready. Hence your map is initialized after the document.ready. You could instead wrap your other code in the $(window).load
$(window).load(function(){
your code here
});

Related

Google Map JavaScript Error(s)

I am trying to install a Google Map via JavaScript on to my website which will have multiple markers. I am getting several errors and I cannot figure them out or resolve them. Please can someone help me?
The map:
<div id="map-canvas"></div>
I am loading the following JavaScript in the footer (below the map-canvas):
<!-- Google Map -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=API REMOVED&callback=initMap" type="text/javascript"></script>
<script type="text/javascript" src="js/map.js"></script>
In my map.js I have:
// necessary variables
var map;
var infoWindow;
// markersdata variable stores the information necessary to each marker
var markersData = [{
lat: 40.6386333,
lng: -8.745,
name: "Camping Praia da Barra",
address1: "Rua Diogo Cão, 125",
address2: "Praia da Barra",
postalCode: "3830-772 Gafanha da Nazaré"
},
{
lat: 40.59955,
lng: -8.7498167,
name: "Camping Costa Nova",
address1: "Quinta dos Patos, n.º 2",
address2: "Praia da Costa Nova",
postalCode: "3830-453 Gafanha da Encarnação"
},
{
lat: 40.6247167,
lng: -8.7129167,
name: "Camping Gafanha da Nazaré",
address1: "Rua dos Balneários do Complexo Desportivo",
address2: "Gafanha da Nazaré",
postalCode: "3830-225 Gafanha da Nazaré"
}
];
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(40.601203, -8.668173),
zoom: 9,
mapTypeId: 'roadmap',
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
// a new info window is created
infoWindow = new google.maps.InfoWindow();
// event that closes the info window with a click on the map
google.maps.event.addListener(map, 'click', function() {
infoWindow.close();
});
// finally displaymarkers() function is called to begin the markers creation
displayMarkers();
}
google.maps.event.addDomListener(window, 'load', initialize);
// this function will iterate over markersdata array
// creating markers with createmarker function
function displayMarkers() {
// this variable sets the map bounds according to markers position
var bounds = new google.maps.LatLngBounds();
// for loop traverses markersdata array calling createmarker function for each marker
for (var i = 0; i < markersData.length; i++) {
var latlng = new google.maps.LatLng(markersData[i].lat, markersData[i].lng);
var name = markersData[i].name;
var address1 = markersData[i].address1;
var address2 = markersData[i].address2;
var postalCode = markersData[i].postalCode;
createMarker(latlng, name, address1, address2, postalCode);
// marker position is added to bounds variable
bounds.extend(latlng);
}
// finally the bounds variable is used to set the map bounds
// with fitbounds() function
map.fitBounds(bounds);
}
// this function creates each marker and it sets their info window content
function createMarker(latlng, name, address1, address2, postalCode) {
var marker = new google.maps.Marker({
map: map,
position: latlng,
title: name
});
// this event expects a click on a marker
// when this event is fired the info window content is created
// and the info window is opened.
google.maps.event.addListener(marker, 'click', function() {
// creating the content to be inserted in the infowindow
var iwContent = '<div id="iw_container">' +
'<div class="iw_title">' + name + '</div>' +
'<div class="iw_content">' + address1 + '<br />' +
address2 + '<br />' +
postalCode + '</div></div>';
// including content to the info window.
infoWindow.setContent(iwContent);
// opening the info window in the current map and at the current marker location.
infoWindow.open(map, marker);
});
}
The errors that I am getting are:
1. Uncaught ReferenceError: google is not defined at map.js:52
2. Uncaught Qb
What does this mean?
You should be passing the name of your map initialisation function (initialize) in the callback query parameter of the google maps URL:
<script async defer src="https://maps.googleapis.com/maps/api/js?key=API REMOVED&callback=initialize" type="text/javascript"></script>
You also need to load your javascript file before loading the google maps API to ensure that your initialisation function is defined when the callback is called:
<script type="text/javascript" src="js/map.js"></script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=API REMOVED&callback=initialize" type="text/javascript"></script>
You're loading the Google API async.
<script async defer src="https://maps.googleapis.com/maps/api/js?key=API REMOVED&callback=initMap" type="text/javascript"></script>
Which means your map.js is being executed before it's loaded, in addition: the callback is 'initMap' which isn't doing anything in your own map.js at this moment.
google.maps.event.addDomListener(window, 'load', initialize);
Remove this line, and change the callback function in your script to initialize.
This line google.maps.event.addDomListener(window, 'load', initialize);
should be in your initialize function cos at the point where it is as your error says, it has not been loaded
Ok, let's looking for what is happening here. You have imported the g maps dependencies with this:
<script async defer src="https://maps.googleapis.com/maps/api/js?key=API REMOVED&callback=initMap" type="text/javascript"></script>
Look at that "async" word. That says that the js file will be loaded asynchronously. Now, look at the src attr:
https://maps.googleapis.com/maps/api/js?key=API_REMOVED&callback=initMap
The attribute callback in the query string defines a JS function that you need have in your code, that will be executed when the async load is finished. You don't have this function in your code,so you should create it with the inialization of your map.
Maybe, putting all your JS code into this will works:
function initMap(){
// your code here
}

Call google maps api event addListener using dart:js

In the Google Maps API v3 they have stated that we need to do this to open the infowindow when the marker gets clicked:
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map,marker);
});
Now I am trying to duplicate this in dart using the js library. So far I have something like this:
final google_maps = context['google']['maps'];
var myLatlng = [43.5, -6.5];
var center = new JsObject(google_maps['LatLng'], myLatlng);
var mapTypeId = google_maps['MapTypeId']['ROADMAP'];
var mapOptions = new JsObject.jsify({
"center": center,
"zoom": 8,
"mapTypeId": mapTypeId
});
var map = new JsObject(google_maps['Map'], [querySelector('#map-canvas'), mapOptions]);
var marker = new JsObject(google_maps['Marker'], [new JsObject.jsify({
'position': center,
'map': map,
'title': 'Hello World!'
})]);
var tooltip = '<div id="content">Info window coontent</div>';
var infowindow = new JsObject(google_maps['InfoWindow'], [new JsObject.jsify({
"content": tooltip
})]);
google_maps['event'].callMethod('addListener', [marker, 'click', () {
infowindow.callMethod('open',[map,marker]);
}]);
The issue is that I set the 'addListener' method through google_maps['event'], but when I click the marker, I get a NoSuchMethodError:
Closure call with mismatched arguments: function 'call'
NoSuchMethodError: incorrect number of arguments passed to method named 'call'
Receiver: Closure: () => dynamic
Tried calling: call(Instance of 'JsObject')
Found: call()
I am aware that there is a google_maps dart package, but I want the interact with the javascript api using dart's js library.
Thanks in advance.
Your closure has zero arguments.
() {
infowindow.callMethod('open',[map,marker]);
}
You just have to give it an argument as stated in the error message:
(event) {
infowindow.callMethod('open',[map,marker]);
}

Google forEach map.data feature not called

I am trying to load a GeoJSON to the google maps javascript api and then process the GeoJSON by calling map.data.forEach . I cant get the map.data.forEach function to work it seems that it is never called.
The GeoJSON gets loaded fine and is displayed on my map.
Any suggestions why map.data.forEach would not work here?
Here is my code:
var myMap;
function initialize() {
// Create a simple map.
myMap = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 8,
center: {
lat: 48.2081743,
lng: 16.3738189
}
});
}
function calculate(map) {
console.log("calculating")
map.data.forEach(function (feature) {
console.log("tester");
});
console.log("end calculating");
}
function loadGeoJson(map) {
map.data.loadGeoJson('mini.json');
}
google.maps.event.addDomListener(window, 'load', function () {
initialize();
loadGeoJson(myMap);
calculate(myMap);
});
This is caused by javascripts asynchronous nature. When you have the code
loadGeoJson(myMap);
calculate(myMap);
and loadGeoJson loads an external resource, calculate will most likely be executed before loadGeoJson has finished. It is very easy to reproduce your problem.
Unfortunately there is no callback opportunity in google.maps.Data::loadGeoJson, but if you wrap the call of calculate into a small setTimeout, then you should be good :
loadGeoJson(myMap);
setTimeout(function() {
calculate(myMap);
}, 500);
see a fiddle with your code from above -> http://jsfiddle.net/SAS6Q/
You can also use jQuery and Ajax to load your JSON synchronously to avoid setting time delays:
function loadGeoJson(map) {
$.ajax({
url: mini.json,
dataType: 'json',
async: false,
success: function(data)
{var features = map.data.addGeoJson(data);}
});
}

Durandal SPA Google Map API Map Centering

There are a few posts regarding issues with google map api centering properly. I understand the following resizes the map:
google.maps.event.trigger(map, 'resize');
I was able to get the map to display properly within the div element on first page display. However, when navigating back to the html page that holds the map, only a fraction of the map displays within the div. The problem i'm having is figuring out how to incorporate this resize trigger. I'm new to SPA's and Durandal, here is my viewmodel responsible for the map:
define(['async!https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false'], function () {
var vm = {
title: 'Home View',
attached: initialize,
activate: function () {
toastr.success('Map View Activated');
}
};
return vm;
function initialize() {
var mapOptions = {
zoom: 10,
center: new google.maps.LatLng(-34.397, 150.644),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
}
});
Sure, you'd want to do this when the map is visible, i.e. it has a height and width. The best event for this is typically the composition complete event. So:
var vm = {
title: 'Home View',
attached: initialize,
activate: function () {
toastr.success('Map View Activated');
},
compositionComplete: function() {
google.maps.event.trigger(map, 'resize');
}
};
See the list and description of all callbacks here: Hooking Lifecycle Callbacks

How to add markers to google map dynamically?

With the first script I create the map and add a marker to it with the second script (which does not work). I need to add the markers with a separate script because the marker data is retreived from my database. The query loops through records and provides the script with name and coordinates for markers. I know the problem is about the variable "map". If I move the marker script to within first script, it works. Can someone help me with this please?
<script type="text/javascript">
var map;
function GoogleLoadMap() {
var latLng = new google.maps.LatLng(35.337186, 33.337439);
var homeLatLng = new google.maps.LatLng(35.314246, 33.389347);
map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 12,
center: latLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
};
</script>
<script type="text/javascript">
var marker<%=iii%> = new MarkerWithLabel({
position: new google.maps.LatLng(<%=lat%>, <%=lon%>),
draggable: true,
map: map,
labelContent: "<%=HNAME%>",
labelAnchor: new google.maps.Point(22, 0),
labelClass: "labels", // the CSS class for the label
labelStyle: {opacity: 0.75}
});
var iw<%=iii%> = new google.maps.InfoWindow({
content: "<%=HNAME%>"
});
google.maps.event.addListener(marker<%=iii%>, "click", function (e) {
iw<%=iii%>.open(map, marker<%=iii%>); });
</script>
It is a timing problem. The map, which is initialized in the GoogleLoadMap() function (which I assume is run on the window load event, but you don't provide that code), is initialized after you create all your markers. You need to either initialize your markers after the map is initialized (inside the GoogleLoadMap function), or call the .setMap method on all the markers after initializing the map.