Reuse already loaded JavaScript - javascript

The goal
Reuse already loaded JavaScript correctly.
The problem
I'm generating a map dynamically using Google Maps API V3 and I need to reuse it. How?
The scenario
On Index.html, there's the following script:
var gMapsLoaded = false;
window.gMapsCallback = function () {
gMapsLoaded = true;
$(window).trigger('gMapsLoaded');
}
window.loadGoogleMaps = function () {
if (gMapsLoaded) return window.gMapsCallback();
var script_tag = document.createElement('script');
script_tag.setAttribute("type", "text/javascript");
script_tag.setAttribute("src",
"http://maps.google.com/maps/api/js?sensor=false&callback=gMapsCallback");
(document.getElementsByTagName("head")[0]
|| document.documentElement).appendChild(script_tag);
}
When I click on some button to show the map, my app invokes this script:
[...]
var geocoder;
var map;
var address = context.address();
function initialize() {
var mapDiv = document.getElementById("map_canvas");
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(-34.397, 150.644);
var myOptions = {
zoom: 15,
center: latlng,
mapTypeControl: true,
mapTypeControlOptions:
{ style: google.maps.MapTypeControlStyle.DROPDOWN_MENU },
navigationControl: true,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(mapDiv, myOptions);
if (geocoder) {
geocoder.geocode({ 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
map.setCenter(results[0].geometry.location);
var infowindow = new google.maps.InfoWindow(
{
content: '<b>' + address + '</b>',
size: new google.maps.Size(150, 50)
});
var marker = new google.maps.Marker({
position: results[0].geometry.location,
map: map,
title: address
});
google.maps.event.addListener(marker, 'click', function () {
infowindow.open(map, marker);
});
} else {
alert("No results found");
}
} else {
alert
("Geocode was not successful
for the following reason: " + status);
}
});
}
gMapsLoaded = false;
}
$(window).on('gMapsLoaded', initialize);
window.loadGoogleMaps();
As you can see, the application is always calling the loadGoogleMaps(); function that calls the external .js file. If I click in the 5 different maps, I get 5 scripts with the same proposal.
Someone have any idea to solve this?
Duplicated question?
Yes, I think that the essence of the question is duplicated, but the nucleus isn't.

As you can see, the application is always calling the
loadGoogleMaps(); function that calls the external .js file. If I
click in the 5 different maps, I get 5 scripts with the same proposal.
That is incorrect. After the first time it completely loads, the if statement on the first line will return early, preventing you from including it multiple times.
There's nothing wrong with the way that's written.
jsFiddle
var gMapsLoaded = false;
window.gMapsCallback = function () {
gMapsLoaded = true;
$(window).trigger('gMapsLoaded');
}
window.loadGoogleMaps = function () {
if (gMapsLoaded) return window.gMapsCallback();
console.log('Generating new script tag');
var script_tag = document.createElement('script');
script_tag.setAttribute("type", "text/javascript");
script_tag.setAttribute("src",
"http://maps.google.com/maps/api/js?sensor=false&callback=gMapsCallback");
(document.getElementsByTagName("head")[0]
|| document.documentElement).appendChild(script_tag);
}
$(window).on("gMapsLoaded",function(){
console.log("gMapsLoaded");
});
$(function(){
$("button").on("click",window.loadGoogleMaps);
});
Now, if you were to click it 5 times really fast when it isn't already loaded, it could potentially load it multiple times. You should call that function on it's own before a click event would normally happen to prevent that.
Update:
At the end of your initialize() method, you're using gMapsLoaded = false; which causes the above code to once again request a new script tag. Simply remove/comment out that line.

Related

How to load google maps as callback?

I have defined an ajax function that get some records from the database, after the data was taken I want load google maps, so I passed the function as callback:
get_records = function (callback) {
var postUrl = "someurl";
var postData =
{
csrfToken: "token",
};
$.post(postUrl, postData, function (response) {
callback(response);
});
};
this is the callback:
get_records(function(result){
init_map();
});
where init_map is:
init_map = function () {
var map;
google.maps.event.addDomListener(window, "load", function () {
map = new google.maps.Map(document.getElementById("map"), {
center: new google.maps.LatLng(33.808678, -117.918921),
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var infoWindow = new google.maps.InfoWindow();
function createMarker(options, html) {
var marker = new google.maps.Marker(options);
if (html) {
google.maps.event.addListener(marker, "click", function () {
infoWindow.setContent(html);
infoWindow.open(options.map, this);
});
}
return marker;
}
var marker0 = createMarker({
position: new google.maps.LatLng(40.9117877, 14.7679659),
map: map,
icon: "../assets/img/marker-green.png"
}, "<h1 class='black-content'>Marker 0</h1><p>This is the home marker.</p>");
});
return map;
};
if I place the init_map function outside get_records the map is displayed, but with the code above I get no map displayed, why?
If there's no response coming from the ajax post, the callback will never be called.
A better approach is to use the Promise interface:
var jqxhr = $.post("example.php", function() {
console.log("success")
}).done(function() {
// call init_map() on done?
}).fail(function() {
// call init_map() on error?
}).always(function() {
// call init_map() regardless the response?
})
Also, you're using google.maps.event.addDomListener to add a listener during window load. If you're sure that your page is loaded before making the ajax post, you don't need this listener. You'll only need to create a new map inside the init_map function.

Repeating a function every x seconds

I am trying to repeat the function "refresh(geocoder, map, infowindow)" every x seconds but it won't work. Below is what the code that i have tried in html and javascript. Any help given is appreciated.
I am trying to repeat the function "refresh(geocoder, map, infowindow)" every x seconds but it won't work. Below is what the code that i have tried in html and javascript. Any help given is appreciated.
Thank you.
function initMap() {
var geocoder = new google.maps.Geocoder;
var infowindow = new google.maps.InfoWindow;
myAddress = document.getElementById("address");
function refresh(geocoder, map, infowindow) {
$.ajax({
type: "GET",
url: 'http://localhost/scripts/retrievegeolocation.php',
dataType: "json",
success: function(data)
{
document.getElementById("Lat").innerHTML = data.Lat; // show response from the php script.
document.getElementById("Lng").innerHTML = data.Lng;
var latlng = {lat: parseFloat(data.Lat), lng: parseFloat(data.Lng)};
geocoder.geocode({'location': latlng}, function(results, status) {
if (status === 'OK') {
if (results[0]) {
map.setZoom(15);
var marker = new google.maps.Marker({
position: latlng,
map: map,icon:'http://localhost/img/car.png',
});
infowindow.setContent(results[0].formatted_address);
infowindow.open(map, marker);
myAddress.innerHTML="Address: " + results[0].formatted_address;
} else {
window.alert('No results found');
}
} else {
window.alert('Geocoder failed due to: ' + status);
}
});
}
});
}
<br/><center> LAT : <p id="Lat" name="Lat" value=" "></p></center><br/>
<center>LNG : </center>
<center><p id="Lng" name="Lng" value=" "></p></center>
<center><p style="font-size:20px;" id="address"></p></center>
<button onclick="function() {
refresh(geocoder, map, infowindow);
}">Try it</button>
It appears that you are missing a closing parenthesis for the function initMap()
I have removed all the code inside and called the dummy functions. It is working fine. Below is the code snippet. Copy paste this into browser console to run this.
function initMap() {
function refresh(geocoder, map, infowindow) {
alert(' refresh');
}
setInterval(refresh, 1000);
}
initMap();
Your button that is calling refresh(geocoder, map, infowindow) doesn't know what geocoder, map, or infowindow are. Two of those items are instantiated inside the initMap() function which is presumably the async loading Google javascript's callback function and map was never instantiated.
Assuming you have an element with the id of "map", put var map = document.getElementById("map"); close to the top of the initMap() function and then try adding this code within the initMap() function after you declare the refresh function.
setInterval( function() {
refresh(geocoder, map, infowindow);
}, 20 );

IndexedDB error: Uncaught DataCloneError: Failed to execute 'put' on 'IDBObjectStore': An object could not be cloned

I am using the Google maps API along with the HTML 5 geolocation API to display my position as a marker on a map. Once this marker is displayed I have a simple on marker double-click function that saves a new marker to my current position using indexedDB. Everything goes well until the Object is about to be stored, then I received the message "Uncaught DataCloneError: Failed to execute 'put' on 'IDBObjectStore': An object could not be cloned." in the console. my code is as follows:
function initialize() {
var mapProperties = { // Set the maps properties
center: new google.maps.LatLng(55.8580, -4.2590),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map-overview"), mapProperties); //Display the map in the map-overview div
function NogeoLocation(e) { //A function to handle users that do not have Geolocation
if (e) {
var content = 'Error: Unfortunately the Geolocation service failed.';
} else {
var content = 'Error: Sorry, Your web browser doesn\'t support geolocation.';
}
var options = { //Error options
map: map,
position: new google.maps.LatLng(60, 105), //Set new position on Error
content: content //Display error message
};
var infowindow = new google.maps.InfoWindow(options);
map.setCenter(options.position);
}
//Using HTML5 Geolocation
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
var position = new google.maps.LatLng(position.coords.latitude,
position.coords.longitude);
var contentString = "Here is your current location!" + "<button onclick='myBtn()'>Save</button>"
var infowindow = new google.maps.InfoWindow({
content: contentString
});
var marker = new google.maps.Marker({
position: position,
map: map,
title: 'My House'
});
google.maps.event.addListener(marker, 'click', function () {
infowindow.open(map, marker);
});
var db;
function indexedDBOk() {
return "indexedDB" in window;
}
google.maps.event.addListener(marker, 'dblclick', function () {
alert("dbl Click");
console.log(position);
if (!indexedDBOk) return;
var openRequest = indexedDB.open("idarticle_people", 1);
openRequest.onupgradeneeded = function (e) {
var thisDB = e.target.result;
if (!thisDB.objectStoreNames.contains("people")) {
thisDB.createObjectStore("people");
}
}
openRequest.onsuccess = function (e) {
console.log("running onsuccess");
db = e.target.result;
var transaction = db.transaction(["people"], "readwrite");
var store = transaction.objectStore("people");
//Define a marker
var marker = {
position: position,
map: map,
title: 'New Marker'
}
console.log(marker);
console.log("about to perform add");
//Perform the add
var request = store.put(marker, 1);
console.log("added");
request.onerror = function (e) {
console.log("Error", e.target.error.name);
//some type of error handler
}
request.onsuccess = function (e) {
console.log("Woot! Did it");
}
}
openRequest.onerror = function (e) {
//Do something for the error
}
});
map.setCenter(position);
}, function () {
NogeoLocation(true); // Refers to NogeoLocation function
});
} else {
// If the user's browser doesn't support Geolocation
NogeoLocation(false);
} //End of HTML5 GeoLocation
} // End of the function that initializes Google Maps
google.maps.event.addDomListener(window, 'load', initialize); //On page load, execute initialize()
marker can't be cloned because the object stored in the map-property contains a reference to a DOMNode(#map-overview), which can't be cloned (see:Things that don't work with structured clones).
Remove the map-property, it will not be re-usable at all because the google.maps.Map-instance will not exist when you retrieve the marker later.
I discovered that the reason for the error was to try to add an object that was not recognized to a cache.
this.storage.set ("page", HomePage);
I switched to a string and it worked
this.storage.set ("page", "HomePage");

Google Maps: Passing extra arguments into GeoCoder for InfoWindows

This is my first post. I'm completely stuck and could use some help with adding infoWindows to Google Maps. The data I'm actually going to use (NOT the API I used here) doesn't have lat/lon and has multiple values.
Things are fine until infoWindow, but I can't pass any other arguments into the geocoder callback. Thanks in advance for the help!
Credit goes to Minghui Yu: http://goo.gl/zvAKZ8. Mine uses different data for the infowindow and will have probably about 30 markers.
Here's the relevant code JS FIDDLE:
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 3,
center: new google.maps.LatLng(0, 0),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var infowindow = new google.maps.InfoWindow();
var marker;
var i;
var mapData;
var locations = [];
$(document).ready(function () {
$.ajax({
url: 'http://api.openweathermap.org/data/2.5/weather?q=London,uk',
async: false,
success: function (mapData) {
locations.push(mapData.name);
}
});
initialize();
});
function initialize() {
setMarkers(map, locations);
}
function setMarkers(map, address) {
for (var i = 0; i < address.length; i++) {
setMarker(map, address[i])
}
}
function setMarker(map, address) {
geocoder = new google.maps.Geocoder();
geocoder.geocode({
'address': address
},
function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
position: results[0].geometry.location,
map: map
});
google.maps.event.addListener(marker,
"click", function () {
//HAVING THE PROBLEM HERE. Not sure how to separate this from the callback.
infowindow.setContent(mapData.main.temp);
// But this works if you run it:
//infowindow.setContent(address);
infowindow.open(map, marker);
});
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
You've declare myData as a global variable.
But here you have mapData as parameter of ajax success callback.
$(document).ready(function () {
$.ajax({
url: 'http://api.openweathermap.org/data/2.5/weather?q=London,uk',
async: false,
success: function (mapData) { //locally scoped which can't override
locations.push(mapData.name);
}
});
This will not override the global variable.
Instead do like this
var gmapData = {};
and use it like
$(document).ready(function () {
$.ajax({
url: 'http://api.openweathermap.org/data/2.5/weather?q=London,uk',
async: false,
success: function (mapData) {
locations.push(mapData.name);
gmapData = mapData; //assign mapData to global variable
}
});
Now use in infoWindow
google.maps.event.addListener(marker, "click", function () {
//infowindow.setContent() will accept only string
//whereas temp is numeric, so convert to string
infowindow.setContent(gmapData.main.temp.toString());
infowindow.open(map, marker);
});
JSFiddle

Geocode Javascript problem

I wonder whether someone may be able to help me please.
Because of loading issues, I've moved the map options code to my HTML form, rather than it being in a separate Javascript file.
The problem is that I now can't get the Geocode functionality to work. I've added my code below. I'm sure it must be something simple, but I'm a little perplexed by this. I just wondered whether it would be at all possible please that someone could let me know where I've gone wrong.
Many thanks
function geocode() {
// This is defining the global variables
var geocoder, marker;
// This is making the link with the 'Search For Location' HTML form
var form = document.getElementById('searchforlocationform');
// This is catching the forms submit event
form.onsubmit = function() {
// This is getting the Address from the HTML forms 'Address' text box
var address = document.getElementById('inputaddress').value;
// This is making the Geocoder call
getCoordinates(address);
// This is preventing the form from doing a page submit
return false;
}
}
function geocodePosition(pos) {
geocoder.geocode({
latLng: pos
},
function(responses) {
if (responses && responses.length > 0) {
updateMarkerAddress(responses[0].formatted_address);
} else {
updateMarkerAddress('Cannot determine address at this location.');
}
});
}
//New Code
function updateMarkerStatus(str) {
document.getElementById('markerStatus').innerHTML = str;
}
//Changed 'address' to 'returnedaddress'
function updateMarkerAddress(str) {
document.getElementById('returnedaddress').value= str;
}
// This creates the function that will return the coordinates for the address
function getCoordinates(address) {
// This checks to see if there is already a geocoded object. If not, it creates one
if(!geocoder){geocoder = new google.maps.Geocoder();}
// This is creating a GeocoderRequest object
var geocoderRequest = {address: address}
// This is making the Geocode request
geocoder.geocode(geocoderRequest, function(results, status) {
// Check if status is OK before proceeding
if (status == google.maps.GeocoderStatus.OK) {
// Center the map on the returned location
map.setCenter(results[0].geometry.location);
// Check to see if we've already got a Marker object
if (!marker) {
map.setZoom(16);
marker = new google.maps.Marker({
map: map, draggable:true
});
}
// Setting the position of the marker to the returned location
marker.setPosition(results[0].geometry.location);
// Add dragging event listeners.
google.maps.event.addListener(marker, function() {
updateMarkerAddress;
});
//This fills out the 'Latitude' and 'Longitude' text boxes on the HTML form
document.getElementById('osgb36lat').value= results[0].geometry.location.lat();
document.getElementById('osgb36lon').value= results[0].geometry.location.lng();
//This allows the marker to be draggable and tells the 'Latitude' and 'Longitude' text boxes on the HTML form to update with the new co-ordinates as the marker is dragged
google.maps.event.addListener(marker,'dragend',
function() {
updateMarkerStatus;
geocodePosition(marker.getPosition());
document.getElementById('osgb36lat').value = marker.position.lat();
document.getElementById('osgb36lon').value = marker.position.lng();
});
// Update current position info.
latLng = [marker.position.lat(), marker.position.lng()].join(', ');
geocodePosition(marker.getPosition());
var point = marker.getPosition();
map.panTo(point);
}
}
)
}
<script type="text/javascript">
(function() {
window.onload = function(){
var latlng = new google.maps.LatLng(54.312195845815246,-4.45948481875007);
var options = {
zoom: 6,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl: true,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
position: google.maps.ControlPosition.TOP_RIGHT
},
navigationControl: true,
navigationControlOptions: {
style: google.maps.NavigationControlStyle.ZOOM_PAN,
position: google.maps.ControlPosition.TOP_LEFT
},
scaleControl: true,
scaleControlOptions: {
position: google.maps.ControlPosition.BOTTOM_LEFT
}
};
var map = new google.maps.Map(document.getElementById('map'), options);
}
})();
</script>
You seen to be trying to call updateMarkerAddress with updateMarkerAddress; and updateMarkerStatus with updateMarkerStatus;, here you are missing (/*some param*/).
What are the loading issues? Maybe if you show your html someone could help with that too.

Categories