Initialize Google map after DOM content has loaded - javascript

As stated in the title, I have my lng and lat values in my DOM where I'm trying to display the map location based on that 2 values in my DOM however the map isn't display any location as it is in gray color, i suspect that the initMap function is executing before the content has been loaded. Is there a way to initialize the map after the content has been loaded? Here are some of my codes.
Controller
public function show($id)
{
$report = Report::find($id);
return view('report',compact('report'));
}
View
<p class="title" id="reportId" data-id="{{$report->id}}" data-lat="{{$report->latitude}}"
data-lng="{{$report->longitude}}">{{$report->title}}</p>
JavaScript
function initMap() {
const latData = parseFloat(document.getElementById('reportId').getAttribute('data-lat'));
const lngData = parseFloat(document.getElementById('reportId').getAttribute('data-lng'));
console.log(typeof latData);
var options = {
zoom: 15,
center: {
lat : latData,
lng : lngData
}
};
var map = new google.maps.Map(
document.getElementById("map"),
options
);
var marker = new google.maps.Marker({
position: {
lat : 3.119822,
lng : 101.594800
},
map: map
});
}
This is how the map looks
EDIT
I did not include this in the beginning because I assumed it was just an issue with JavaScript however, for more information I'm using Laravel 6.5.2 in this project which is the reason why my lat and lng data are inside an element's dataset.
There are nothing special in my laravel codes just getting the data from database through controller methods and display onto my view at the same time setting a data-lat and data-lng so that in my script i can get the coordinates and populate to a google map view.
I have tried one Laravel Google Map library called Googlmapper but unfortunately I'm getting some error from that library too. It is out of topic but you can check it out here.

I would make use of Document.readyState.
The Document.readyState property describes the loading state of the document.
The readyState of a document can be one of following:
loading
The document is still loading.
interactive
The document has finished loading and the document has been parsed but sub-resources such as images, stylesheets and frames are still loading.
complete
The document and all sub-resources have finished loading. The state indicates that the load event is about to fire.
so in your case:
document.addEventListener('readystatechange', event => {
if (event.target.readyState === 'interactive') {
//
}
else if (event.target.readyState === 'complete') {
initMap();
}
});
Source Mozilla
2nd solution:
If you will load content via ajax after the dom is already loaded and maybe this take some time, you could set up a time out function, but you will never know when the object is loaded.
Then you can track the existence of a dom object and if it is part of the dom content, then read the value and execute your function:
function waitForElement(callback){
if(window.someVariable){
callback();
} else{
setTimeout(waitForElement(callback), 250);
}
}
// execute on load:
waitForElement(initMap);
edit: (based on your comment)
seems to me that the map is initialised but without coords.
I have only rewritten the coords and created a fiddle.
If you have a valid GoogleApiKey, then enter it and the map will be created successfully.
JsFiddle GoogleMaps-example
function initMap() {
const latData = parseFloat(document.getElementById('reportId').getAttribute('data-lat'));
const lngData = parseFloat(document.getElementById('reportId').getAttribute('data-lng'));
var uluru = {lat: latData, lng: lngData};
console.log(typeof latData);
var options = {
zoom: 15,
center: uluru
};
var map = new google.maps.Map(
document.getElementById("map"),
options
);
var marker = new google.maps.Marker({
position: uluru,
map: map
});
}

Solved
Apparently... It was a very careless mistake made by me.
which was flipping the values between lat and lng value which results into a undefined location which is why the map did not display location even thought it has been initialized.

You can change your body tag to be the following:
<body onload="initMap()">
so that once the dom loads, the map will be initialized.

Related

Updating Google Maps Long/Lat

I am trying to update a store location by getting the lat/long of a marker on the google map.
However I get this error:
UpdateStoreDAO.js:7 Uncaught TypeError: Cannot read property 'getPosition' of undefined
at updateItemData (UpdateStoreDAO.js:7)
at UpdateStore.js:68
at IDBOpenDBRequest.request.onsuccess (indexedDB.js:38)
I'm not quite sure why it won't work as getPosition works for adding a store location to the map for a marker. It uses the same Google Maps API as my adding page does and the add page never threw me this error.
The code for the update function (DAO) is:
function updateItemData(marker) {
//User input of item name
var storeLocation = $('#txtStoreLocation').val();
//Get latitude and longitude of current marker position
var eventLat = marker.getPosition().lat();
var eventLng = marker.getPosition().lng();
//Create an item object combining name, desc and price attributes
data.storeLocation = storeLocation;
data.eventLat = eventLat;
data.eventLng = eventLng;
var data = {
'storeLocation' : storeLocation,
'eventLat' : eventLat,
'eventLng' : eventLng
}
//Insert data into indexedDB database
updateOne(data, function(lastID) {
event.preventDefault();
return false;
});
}
The code for the update store js file is (if it's any help):
//mapCenter
var mapCenter = new google.maps.LatLng(51.8979988098144,-2.0838599205017);
//geocoder will be used to convert geographic coordinates (current marker position)
// intop a human-readable address
var geocoder = new google.maps.Geocoder();
//An InfoWindow displays content (usually text or images)
//in a popup window above the map, at a given location.
var infowindow = new google.maps.InfoWindow();
function initialize(){
// Initial map properties
var mapOptions = {
zoom: 15,
center: mapCenter
};
//Create a map object passing the html div placeholder to hold google map
myMap = new google.maps.Map(document.getElementById("mapInput"), mapOptions);
//Create a draggable marker icon in the map
marker = new google.maps.Marker({
map: myMap,
position: mapCenter,
draggable: true
});
}
//Retrieve Item information saved in database
//show in the form
var urlParams = new URLSearchParams(window.location.search);
var itemID = urlParams.get('itemID');
$('#itemID').html("Item ID: " + itemID);
setDatabaseName('dbCatalogue', ['UsersObjectStore', 'ItemsObjectStore']);
setCurrObjectStoreName('ItemsObjectStore');
//Select One function to retrieve data of a specific item
var data;
startDB(function () {
selectOne(itemID, function(result) {
$('#txtStoreLocation').val(result.storeLocation);
$('#txtEventLat').val(result.eventLat);
$('#txtEventLng').val(result.eventLng);
data = result;
})
})
//The addDomListener will be triggered when the HTML page is loaded
//and will execture the initialize function above
google.maps.event.addDomListener(window, 'load', initialize);
//Event handler for form submit button
$('#formUpdateStore').submit(function(event){
// cancels the deafult form submission and handle the event from javascript
event.preventDefault();
//Create an idexedDB database (the name of the database is dbFlogger)
// with two object stores - UsersObjectStore to store user data
// and ItemsObjectStore to store item data
setDatabaseName('dbEvent', ['EventObjStore']);
// For this example, we will store data in ItemsObjectStore
setCurrObjectStoreName('EventObjStore');
//startDB will create a connection with the database and
//execute operations such as save item
startDB(function () {
updateItemData(data);
alert("Store has been updated successfully!");
});
});
I understand it's probably a lot to ask but any help would be appreciated!
(note = comments are a bit off since code has been reused from other pages)
===UPDATE===
I fixed the error by changing updateItemData(data) to updateItemData(marker) in the regular js file.
However, I am now getting a new error:
Uncaught TypeError: Cannot set property 'storeLocation' of undefined
at updateItemData (UpdateStoreDAO.js:11)
at UpdateStore.js:68
at IDBOpenDBRequest.request.onsuccess (indexedDB.js:38)
I'm not quite sure why I'm getting this as storeLocation is defined and there's a property set via user input?

jQuery/Javascript: Google Maps: How to toggle multiple pins on a map?

I have a database of locations which I want to be able to print on a map. Ideally there should be one map with multiple pins for each location you have toggled on. So click a button for location X and it shows up on the map. Click the button for location Y and it shows up on the same map. Click X again and it hides from the map.
Currently I have it so I click on X and the map gets redrawn centered around point X.
Here is the HTML for each button:
<input type='button' data-lat='38.89864400' data-long='-77.05283400'
data-when='20 Aug at 2:00am' value='Location X' class='click' />
The jQuery I'm using is:
jQuery(document).ready(
function initialize() {
jQuery("input.click").click(function() {
showOnMap(jQuery(this).data('lat'), jQuery(this).data('long'), jQuery(this).data('when'));
});
}
);
function showOnMap(lat, long, message) {
var myLatlng = new google.maps.LatLng(lat, long);
var mapOptions = {
zoom: 13,
center: myLatlng
}
var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: message
});
google.maps.event.addDomListener(window, 'load', showOnMap);
}
Is there an easy way to switch from what I have to what I want? I've searched for a while but no one seems to be asking this use case in a browser, just Android (which I'm not doing).
Thanks!
There is an example in the documentation on how to hide/show markers. In short, a marker is:
hidden by setting its map to null
showed by setting its map to map
To do so, you will need to access each marker individually. If you have a definite number of locations, it can be done by naming them with different names (eg var markerLocationX, var markerLocationY, etc). Otherwise, the markers need to be stored in an array.
Supposing you have a definite number of known locations to toggle the markers, your javascript code may look like this:
function toggleMarker(markerName) {
if (markerName.getMap() == null) {
markerName.setMap(map);
} else {
markerName.setMap(null);
}
}

using 2 google maps on 2 different pages, one is working but the second works only after a refresh apparently

I have a site that is using google map api (src="https://maps.googleapis.com/maps/api/js?key=...).
One page has a map with location marker that user can click on it.
When a user click on a map, he may choose to view the detail of that location.
the detailed location includes two maps (a satellite view and a street view).
The problem is that when you land to the second page you only see google map frame but there is no map. In order to get a map I have to include an alert() function that will execute after the first load, then the map shows without problem.
I am a little new to google map api, I don't understand this behavior.
the code for the google maps are in a js file, the html file where the map is inserted is in another file (.php).
So the question is why do I have to reload or use the 'alert(yahoo)' below (that I have commented out) in order for the map to load.. Here is how the code looks like:
function initialize_single_location() {
var currentdate = get_current_date();
$.getJSON(some code go here)
.done(function (data) {
for (i = 0; i < data.length; i++) {
if(some codes go here)
{
position_lat = data[i].lat;
position_long = data[i].long;
address=data[i].address;
city=data[i].city;
state=data[i].state;
zip=data[i].zip;
name=data[i].name;
$('#myAddress').html('<strong>'+data[i].name +'</strong><br>' + data[i].address + '<br>' + data[i].city + ' ' + data[i].state + ' '
+ data[i].zip + '<br>' +'Telephone: Not Provided' + '<br> Fax: Not Provided');
var direction = document.getElementById("directions");
direction.setAttribute("href", "https://www.google.com/maps/dir//"+address+"+"+city+"+"+state+"+"+zip+"");
}
}
})
.fail(function(jqxhr, textStatus, error) {
var err = textStatus + ", " + error;
alert("Request Failed: " + err);
});
//alert('yahoo');
var fenway = new google.maps.LatLng(position_lat, position_long);
var mapOptions = {
center: fenway,
zoom: 18,
mapTypeId: google.maps.MapTypeId.SATELLITE
};
var map = new google.maps.Map(
document.getElementById('map-canvas2'), mapOptions);
var panoramaOptions = {
position: fenway,
pov: {
heading: 34,
pitch: 10
}
};
var panorama = new google.maps.StreetViewPanorama(document.getElementById('pano'),panoramaOptions);
map.setStreetView(panorama);
}
google.maps.event.addDomListener(window, 'load', initialize_single_location);
You have problem because of asynchronous nature of $getJSON() call. It returns immediately and initialization of map starts after that. Variable fenway is most probably undefined so map cannot be properly initialized. That is why alert() helps. While you close the alert window, variables from $getJSON.done() are set and everything works fine after that.
You have to move all that code for map initialization to .done() part of $getJSON() call or make it a function and call it at the end of .done() part.
In your addDomListener, call a function that checks to see if the map-canvas is visible (for landing directly on this page/tab). If so, initialize the map. I also added a document.ready check that calls the visibility check function when switching from another page/tab:
jQuery(document).ready(function ($) {
mapVisible();
});
function mapVisible() {
if (!$("#googft-mapCanvas").is(":visible")) return;
initialize_single_location();
}
//this will call it if you land directly on this page/tab
google.maps.event.addDomListener(window, 'load', mapVisible);
We used this with jQuery tabs, and switching to a second tab doesn't reinitiate the window load event. This worked around that.

Trigger event when google maps fusiontable layer is loading or finished loading?

I'm loading in quite a lot of data from a fusion table using Google Maps Api. I'm adding the data as a layer to the map using the code below (code not relevant has been omitted)
function initialize() {
var tableId = 'xyxyxyxyxyxyxyxyxy';
map = new google.maps.Map(document.getElementById('map-canvas'), {
center: new google.maps.LatLng(51.522416,-0.11673),
zoom: 9,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var layer = new google.maps.FusionTablesLayer();
google.maps.event.addDomListener(
document.getElementById('checkbox_id'),
'click',
function() { filterMap(layer, tableId, map); }
);
}
function filterMap(layer, tableId, map, generated) {
var the_where_query = generate_where()
layer.setOptions({
query: {
select: 'geometry',
from: tableId,
where: the_where_query
},
options : {suppressInfoWindows:true}
});
}
My issue is that there is a big gap between clicking on the the checkbox and the data appearing on the map. I want to be able to listen for an event somehow so that I can
Display a loading div element when the user clicks the checkbox
When layer.setOptions has returned hide the loading div element.
I understand how to do the DOM work with the div, I just can't seem to find a good way of telling if the query has returned from the fusiontable lookup (which can take 1 - 2 seconds sometimes)
You can put a listener to capture if its loaded. status_changed event is created for this.
google.maps.event.addListener(layer, 'status_changed', function() {
--your code here
});
Or, you can use properties_changed event which will be fired after it is loaded.

How to get some information in google maps without click event on marker and show this in a div, other than infoWindow

Hi I am showing some markers on my google map and on click of the marker, I am calling the click event and showing some info about that place to the right side(area other than Map and not as an infoWindow). Now this event gets fired on click, and by default when page loads my div remains blank, How can I have the div the basic information being shown up once the map loads up. I need to show the information that corresponds to the marker that is the center point of the map, and later when the users click the marker icons the info should change and correspond to the particular marker being clicked
I have tried something but it doesn't work:
function loadMap() {
var myLatlng = new google.maps.LatLng(40.46998, -3.68705);
var myOptions = {
zoom: 3,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map"), myOptions);
var places = [];
places.push(new google.maps.LatLng(51.43581, -0.51744));
places.push(new google.maps.LatLng(48.87187, 2.31764));
places.push(new google.maps.LatLng(45.45979, 9.19681));
var infowindow;
for(var i = 0; i<places.length; i++) {
var marker= new google.maps.Marker({
position: places[i],
map: map,
title: 'Place' + i
});
(function (i,marker){
google.maps.event.addListener(marker, 'click' , function() {
infowindow.setContent('PLace Number' + i)
infowindow.open(i, marker)
});
});(i, marker);
}
}
$("document").ready(function () {
loadMap();
});
UPDATE EDITED
Basically I need something like Layer KML features
But the info should come on the right hand side by default for the first time. Later on when the marker is clicked, the info should change. I am also not adamant that I need this info in a kml file(xml is fine with me as well). I can just have a marker and info should popup on click and for the first time be default as well depending on the location of the user.
Bottom Line: I need the info to appear on click of a marker and by default when the page loads the info should appear corresponding to the center point of the map. which means users coming from different locations will see different info's corresponding to their location from where they are coming.(I am centering the map based on users location)
You can use the addDomListener event of the google maps api. Something like this:
<script>
function initialize() {
// Map initialization
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
<body>
<div id="map_canvas"></div>
</body>
Although the above code is Maps Javascript API code, the addDomListener() method binds to the window object of the browser and allows the API to communicate with objects outside of the API's normal domain.
further reading
Actually the basic Idea is that you need to read an XMl and parse the data and and show this in a seperate div on right side., This div you can create dynamically when you load the map e-g:
$("#body").append("<div class='newdiv'></div>")
From the google Docs in the section about InfoWindow:
Note that if you call open() without passing a marker, the InfoWindow
will use the position specified upon construction through the
InfoWindow options object.
So in your code, why don't you simply init your infoWindow and call the open() method? I am not particularly familiar with the api, but how about:
var infowindow = new google.maps.InfoWindow({
content: 'your initial text'
});
infowindow.open();
Or if you need the marker for special purposes on the infowindow, init an marker with the center position and use that in the infowindow.open(your_initial_pos) call.
You can use jQuery to .triger() a click event on the first marker on document.ready:
$(marker).trigger('click');
This will run the code you have already written and make it so when the page loads your div will be populated with data from whatever element you trigger the click on.
When you bind to document.ready you don't need encapsulate document in quotes:
$(document).ready(function () {...});
Or you could use the short-hand if you're into that sort of thing:
$(function () {...});
UPDATE
You can place the trigger function call after your for loop where you are setting up the markers:
for(var i = 0; i<places.length; i++) {
var marker= new google.maps.Marker({
position: places[i],
map: map,
title: 'Place' + i
});
(function (i,marker){
google.maps.event.addListener(marker, 'click' , function() {
infowindow.setContent('PLace Number' + i)
infowindow.open(i, marker)
});
});(i, marker);
//only run on the first marker
if (i === 0) {
//trigger a click event to show the first info-window
$(marker).trigger('click');
}
}
You can fire a tilesloaded event on the map object. Check out the Map reference for events
tilesloaded waits until the map tiles are actually loaded before firing. Using your code, you could do something like this:
function loadMap() {
var myLatlng = new google.maps.LatLng(40.46998, -3.68705);
var myOptions = {
zoom: 3,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map"), myOptions);
google.maps.event.addListener(map, 'tilesloaded', function() {
doSomething();
});

Categories