Solved

Javascript Error - Uncaught TypeError: Object [object global] has no method 'handleApiReady'

Posted on 2013-12-29
9
1,193 Views
Last Modified: 2014-01-14
With the Google Maps async code below I'm seeing this error:
Uncaught TypeError: Object [object global] has no method 'handleApiReady'

The code runs fine but in the console I see this error.

<script src="http://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=handleApiReady"></script>

 <script type="text/javascript">
   $LAB
  	       .script("//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js")	
				    .script("/js/poiaktuell.js")
		  .script("/js/grey.js")
   .script("/js/jquery.slidetabs.min.js")
   .script("/js/jquery.slidetabs.touch.min.js")
   .script("/js/jquery-litelighter.js")

    .wait(function(){

	function handleApiReady() {

	setupAddress();
	mapDiv = document.getElementById(mapDivID);
	var myLatlng = new google.maps.LatLng(0,0);
	var myOptions = {
		zoom: zoomLevel,
			 styles: gmapGreyStyle,
		scrollwheel: true,
		disableDoubleClickZoom: true,
		center: myLatlng,
		mapTypeControl: true,
		mapTypeControlOptions: {
		  style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
		  position: google.maps.ControlPosition.BOTTOM_LEFT
		},
		zoomControl: true,
		zoomControlOptions: {
		  style: google.maps.ZoomControlStyle.LARGE,
  		  position: google.maps.ControlPosition.TOP_LEFT
		},
		panControl: false,
		mapTypeId: google.maps.MapTypeId.ROADMAP,
		overviewMapControl: true,
		overviewMapControlOptions: {
			opened: false
			}
	};
	map = new google.maps.Map(mapDiv, myOptions);
	

	if(directionsMode == 'DRIVING') {
		travMode = google.maps.DirectionsTravelMode.DRIVING;
	} else {
		travMode = google.maps.DirectionsTravelMode.WALKING;
	}
	//streetview stuff
	var tempPanorama = map.getStreetView();

	google.maps.event.addListener(tempPanorama, 'visible_changed', function() {
	    if (tempPanorama.getVisible()) {
			controlToggle("hide");
		} else {
			controlToggle("show");
	    }
	});
	
	infoBox();

	var geocoder = new google.maps.Geocoder();
    var address = startAddress;
    geocoder.geocode( { 'address': address}, function(results, status) {
      if (status == google.maps.GeocoderStatus.OK) {
        map.setCenter(results[0].geometry.location);
   		addressSet = 1;
		searchCenter = results[0].geometry.location;
        getCategories(1);
		createMarker(searchCenter, 0, markerHTML, "pin", "pin","");
//		var trafficLayer = new google.maps.TrafficLayer();
//		trafficLayer.setMap(map);
	    google.maps.event.addListener(map, "dragend", function () {
				controlToggle("show");
			    getCategories(0);
	    });
		mobileScroll(sidebarDivID);
		if (autoGeolocation === true) {
					geotarget();
		}
		if (mapExtra === true) {
			mapPost();
		}
		}
    });

}


	$(document).ready(function() {

		  handleApiReady();
		$('pre').litelighter({clone:false, style:'light', language:'js'});
						  		
		// Auto Height
		$('#auto-height').slidetabs({
			autoHeight      : true,
			touchSupport: true,
			contentAnim: 'fadeOutIn',
			contentAnimSpeed: 100,
			autoHeightSpeed : 900
			
			
		});
  	});		
		 });
</script>

Open in new window

0
Comment
Question by:seopti
  • 4
  • 3
9 Comments
 
LVL 52

Expert Comment

by:Scott Fell, EE MVE
ID: 39745130
I am not familiar with labjs but could it be the order you are loading? http://labjs.com/documentation.php
0
 
LVL 38

Expert Comment

by:Tom Beck
ID: 39745180
Never heard of labjs until now but in reading the documentation, you should also be loading the Maps Api using labjs. As is, you are attempting to call handleApiReady as a callback to the loading of the API, despite the fact that the handleApiReady function is out of scope inside the "wait" function, all before the other includes have been loaded:
<script src="http://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=handleApiReady"></script>

This makes more sense to me (untested):
$LAB
               .script("//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js")      
                            .script("/js/poiaktuell.js")
              .script("/js/grey.js")
   .script("/js/jquery.slidetabs.min.js")
   .script("/js/jquery.slidetabs.touch.min.js")
   .script("/js/jquery-litelighter.js")
   .script("//maps.googleapis.com/maps/api/js?v=3.exp&sensor=false")

    .wait(function(){

      //load the map directly without the handleApiReady function wrapper

...
...

Remove the handleApiReady call from the $(document).ready function.
0
 

Author Comment

by:seopti
ID: 39745242
Thanks for the answer but

1. The google map always has to be loaded first. (otherwise "error google is not defined")
2. The callback is necessary otherwise it will not load ansychronously.

If you view both files below you can see the two different scripts. The first one contains document.write and is not async, the second is async.

http:////maps.googleapis.com/maps/api/js?v=3.exp&sensor=false
http://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=handleApiReady
0
 

Author Comment

by:seopti
ID: 39745246
At stackoverflow there is  working jsfiddle example to load it dynamically, but it's a bit too complicated for me.

stackoverflow.com/questions/3922764/load-google-maps-v3-dynamically-with-ajax
http://jsfiddle.net/fZqqW/94/
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 38

Accepted Solution

by:
Tom Beck earned 500 total points
ID: 39745249
Here is a mockup page with a map that loads asynchronously with the other includes.

Normally, I would like to call handleApiReady() from inside the $(document).ready function to be sure that the map div is available. I cannot do that when using LABjs because the document is ready before the API is loaded because the API is loading asynchronously so the map will fail. Because I cannot use $(document).ready, I have to define the map in the body AFTER the map div is available.
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Untitled Document</title>
<script src="js/LABjs-2.0.3/LAB.min.js" type="text/javascript"></script>
<script>
$LAB
	.script("http://maps.googleapis.com/maps/api/js?v=3.7&sensor=false&callback=handleApiReady")
	.script("http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js")

	.wait(function() {
		
		$(document).ready(function(){
			console.log("doc ready");
		});

	});	
</script>
</head>
<body>
<div id="map" style="width:300px;height:300px"></div>
<script>
function handleApiReady() {
	var myOptions = {
      	center: new google.maps.LatLng(-34.397, 150.644),
      	zoom: 8,
      	mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    var map = new google.maps.Map(document.getElementById("map"), myOptions);	
}
</script>
</body>
</html>

Open in new window


The $(document).ready function has to be inside the "wait" function or it will be called before the jquery library loads. But it's no good to you for loading the map because the map API is loading on a different thread asynchronously.
0
 
LVL 38

Expert Comment

by:Tom Beck
ID: 39745255
The Stackoverflow link shows a Google Maps script written with version 2 of the API. Steer clear of that.
0
 

Author Comment

by:seopti
ID: 39745298
Thank you, I've been trying a few solutions and this is just close. There is just one error "Google is not defined" which means  Google Maps script needs to be loaded first. What I don't understand I have loaded it first  and asynchronous in the head and still this error prevents the website javascript from loading.

This is straight from the Google website.

https://developers.google.com/maps/documentation/javascript/examples/map-simple-async

In the head:

<script>

		function loadScript() {
  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&' +
      'callback=initialize';
  document.body.appendChild(script);
}
</script>

Open in new window




In the body:

 <script type="text/javascript">
   $LAB
  	       .script("//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js")	
				    .script("/js/poiaktuell.js")
		  .script("/js/grey.js")
   .script("/js/jquery.slidetabs.min.js")
   .script("/js/jquery.slidetabs.touch.min.js")
   .script("/js/jquery-litelighter.js")

    .wait(function(){


	function initialize() {

	setupAddress();
	mapDiv = document.getElementById(mapDivID);
	var myLatlng = new google.maps.LatLng(0,0);
	var myOptions = {
		zoom: zoomLevel,
			 styles: gmapGreyStyle,
		scrollwheel: true,
		disableDoubleClickZoom: true,
		center: myLatlng,
		mapTypeControl: true,
		mapTypeControlOptions: {
		  style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
		  position: google.maps.ControlPosition.BOTTOM_LEFT
		},
		zoomControl: true,
		zoomControlOptions: {
		  style: google.maps.ZoomControlStyle.LARGE,
  		  position: google.maps.ControlPosition.TOP_LEFT
		},
		panControl: false,
		mapTypeId: google.maps.MapTypeId.ROADMAP,
		overviewMapControl: true,
		overviewMapControlOptions: {
			opened: false
			}
	};
	map = new google.maps.Map(mapDiv, myOptions);
	

	if(directionsMode == 'DRIVING') {
		travMode = google.maps.DirectionsTravelMode.DRIVING;
	} else {
		travMode = google.maps.DirectionsTravelMode.WALKING;
	}
	//streetview stuff
	var tempPanorama = map.getStreetView();

	google.maps.event.addListener(tempPanorama, 'visible_changed', function() {
	    if (tempPanorama.getVisible()) {
			controlToggle("hide");
		} else {
			controlToggle("show");
	    }
	});
	
	infoBox();

	var geocoder = new google.maps.Geocoder();
    var address = startAddress;
    geocoder.geocode( { 'address': address}, function(results, status) {
      if (status == google.maps.GeocoderStatus.OK) {
        map.setCenter(results[0].geometry.location);
   		addressSet = 1;
		searchCenter = results[0].geometry.location;
        getCategories(1);
		createMarker(searchCenter, 0, markerHTML, "pin", "pin","");
//		var trafficLayer = new google.maps.TrafficLayer();
//		trafficLayer.setMap(map);
	    google.maps.event.addListener(map, "dragend", function () {
				controlToggle("show");
			    getCategories(0);
	    });
		mobileScroll(sidebarDivID);
		if (autoGeolocation === true) {
					geotarget();
		}
		if (mapExtra === true) {
			mapPost();
		}
		}
    });

}


	$(document).ready(function() {

		$('pre').litelighter({clone:false, style:'light', language:'js'});
						  		
		// Auto Height
		$('#auto-height').slidetabs({
			autoHeight      : true,
			touchSupport: true,
			contentAnim: 'fadeOutIn',
			contentAnimSpeed: 100,
			autoHeightSpeed : 900
			
			
		});
  	});		
		 });
</script>

Open in new window

0
 
LVL 38

Expert Comment

by:Tom Beck
ID: 39745326
Where are you calling loadScript()?

You should have either:

window.onload = loadScript;

in a javascript block somewhere or:

<body onLoad="loadScript()">

in the body tag. If you are not calling loadScript() you will get "Google is undefined".

But then, why are you not using my suggestion if you really want the map to load asynchronously? The way you have it, the Maps API is loading synchronously with the LABjs stuff because it's outside of the LABjs stuff. The initialize() function is inside the LABjs "wait" function which means that it will not begin to run until all the includes are loaded. No point in that. The other includes have nothing to do with the map. You might as well run initialize() as soon as the API is ready. Take the initialize function out of the "wait" function and paste it somewhere in the body after the map div. Load the Maps API using LABjs along with the other includes. The callback=handleApiReady will execute the handleApiReady function as soon as the API is ready WHILE the other includes are loading.

Also, putting this:
<script>

		function loadScript() {
  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&' +
      'callback=initialize';
  document.body.appendChild(script);
}
</script>

Open in new window

...inside the head tags has the same affect as putting this:

<script type="text/javascript"  src="http://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=handleApiReady"></script>

...inside the body tags. Use the LABjs instead so the map is truly loading asynchronously and use it in the head section. That's where includes normally go. The Google maps sample code you cite is ignorant of your use of LABjs so it does not apply here. The only important thing in that example is the use of "callback=" to load the map when the API is ready.
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

In this article, we'll look how to sort an Array in JavaScript, including the more advanced techniques of sorting a collection of records either ascending or descending on two or more fields. Basic Sorting of Arrays First, let's look at the …
Nothing in an HTTP request can be trusted, including HTTP headers and form data.  A form token is a tool that can be used to guard against request forgeries (CSRF).  This article shows an improved approach to form tokens, making it more difficult to…
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now