Reputation: 73
I am trying to trigger the marker popup window in leaflet map but having no luck. I am using cluster map which works fine and open the popup window when user clicks on a marker. I need to extend this e.g. passing a parameter through url and open the specific marker based on the url parameter value on page load. I am using the following code for map clustering.
var latlng = L.latLng(-30.81881, 116.16596);
var map = L.map('lmap', { center: latlng, zoom: 6 });
var lcontrol = new L.control.layers();
var eb = new L.control.layers();
//clear map first
clearMap();
//resize the map
map.invalidateSize(true);
//load the map once all layers cleared
loadMap();
//reset the map size on dom ready
map.invalidateSize(true);
function loadMap() {
var markers_array = [];
var roadMutant = L.gridLayer.googleMutant({
type: 'roadmap' // valid values are 'roadmap', 'satellite', 'terrain' and 'hybrid'
}).addTo(map);
//add the control on the map
lcontrol= L.control.layers({
Roadmap: roadMutant
}, {}, {
collapsed: false
}).addTo(map);
var markers = L.markerClusterGroup({chunkedLoading: true, spiderfyOnMaxZoom: true, maxClusterRadius: 80, showCoverageOnHover: true });
//clear markers and remove all layers
markers.clearLayers();
$.ajax({
type: "GET",
url: appUrl + "/Home/map",
data: {'atype': st},
dataType: 'json',
contentType: 'application/x-www-form-urlencoded',
success: function (data) {
$.each(data, function (i, item) {
var img = (item.IconUrl).replace("~", "");
var Icon = L.icon({ iconUrl: img, iconSize: [42, 42] });
var marker = L.marker(L.latLng(item.Latitude, item.Longitude), { icon: Icon }, { title: item.Name });
var content = "<div class='infoDiv'><h3><img src='" + appUrl + img + "' width='24' />" + item.Name + "</h3><p>" + item.Title + "</p><a href='#' data-value='" + item.AlertId + "' class='btn btn-success btn-sm alertInfo' data-toggle='modal' data-target='#alertDetails'>Details</a></div>";
marker.bindPopup(content);
markers.addLayer(marker);
//add the marker to array
markers_array.push(marker);
});
}
})
.done(function () {
$(".loadingOverlay").hide();
map.invalidateSize(true);
});
//add the markers to the map
map.addLayer(markers);
}
I have tried to implement the following custom click event but no luck.
function markerFunction(id) {
alert(markers_array.length);
for (var i = 0; i < markers.length; ++i) {
var mid = markers_array[i]["_leaflet_id"];
if (mid == id) {
alert("opening " + id);
map.markers(id).openPopup();
}
}
}
//trigger on link click
$("a").click(function () {
var id = $(this).attr("id");
alert(id);
markerFunction(id);
});
Help is much appreciated. Thanks in advance.
Upvotes: 0
Views: 7497
Reputation: 73
After spending too much time on this, I have come up with a different approach. Pass a parameter through URL as hash (#) value. Grab the value using jQuery selector and fetch data for that record then open the popup on the map. Here is my second code block -
$(function () {
var hash = window.location.hash.substr(1);// "90aab585-1641-43e9-9979-1b53d6118faa";
if (!hash) return false;
//show loading
$(".loadingOverlay").show();
$.ajax({
type: "GET",
url: appUrl + "/Home/GetAlert/"+hash,
dataType: 'json',
contentType: 'application/x-www-form-urlencoded',
success: function (data) {
if (!data.status)
{
$('#msg').html(data.message).attr("class","alert alert-warning");
$(".loadingOverlay").hide();
return false;
}
$.each(data.message, function (i, item) {
var popupLoc = new L.LatLng(item.Latitude, item.Longitude);
var popupContent = "<div class='infoDiv'><h3><img src='" + appUrl + img + "' width='24' />" + item.Name + "</h3><p>" + item.Title + "</p><a href='#' data-value='" + item.AlertId + "' class='btn btn-success btn-sm alertInfo' data-toggle='modal' data-target='#alertDetails'>Details</a></div>";
//initialize the popup;
var popup = new L.Popup();
//set latlng
popup.setLatLng(popupLoc);
//set content
popup.setContent(popupContent);
map.setView(new L.LatLng(item.Latitude, item.Longitude), 8);
//display popup
map.addLayer(popup);
});
}
})
.done(function () {
$(".loadingOverlay").hide();
map.invalidateSize(true);
});
});
Upvotes: 0
Reputation: 19288
loadMap()
acquires its data asynchronously. Anything that works with that data (or anything derived from that data) must do so in a way that takes account of the asynchronism, typically in a chained .then()
.
As it stands, markers are created asynchronously but the click handler is independently defined and attached. Delivering markers_array
(and markers
?) via a promise returned from loadMap()
will allow the necessary marker data to be fully populated at the point of attachment and brought into scope of the click handler.
I would write something like this :
var latlng = L.latLng(-30.81881, 116.16596);
var map = L.map('lmap', { center: latlng, zoom: 6 });
var lcontrol = new L.control.layers(); // necessary?
var eb = new L.control.layers(); // necessary?
clearMap(); // why, it's only just been created?
map.invalidateSize(true);
loadMap(map).then(function(obj) {
$(".loadingOverlay").hide();
map.invalidateSize(true); // again?
$("a").click(function(e) { // jQuery selector probably needs to be more specific
e.preventDefault();
var id = $(this).attr('id');
for(var i=0; i<obj.markers_array.length; ++i) {
if(obj.markers_array[i]._leaflet_id == id) {
map.markers(id).openPopup(); // if `map.markers` is correct, maybe you don't need obj.markers?
break; // break out of `for` loop on success.
}
}
});
return obj;
});
function loadMap(map) {
var roadMutant = L.gridLayer.googleMutant({ type: 'roadmap' }).addTo(map);
var lcontrol = L.control.layers({Roadmap: roadMutant}, {}, {collapsed: false}).addTo(map);
return $.ajax({
type: 'GET',
url: appUrl + '/Home/map',
data: {'atype': st},
dataType: 'json',
contentType: 'application/x-www-form-urlencoded'
}).then(function (data) {
var markers = L.markerClusterGroup({chunkedLoading: true, spiderfyOnMaxZoom: true, maxClusterRadius: 80, showCoverageOnHover: true });
markers.clearLayers();
var markers_array = $.map(data, function(item) {
var img = (item.IconUrl).replace("~", "");
var Icon = L.icon({ iconUrl: img, iconSize: [42, 42] });
var marker = L.marker(L.latLng(item.Latitude, item.Longitude), { icon: Icon }, { title: item.Name });
var content = "<div class='infoDiv'><h3><img src='" + appUrl + img + "' width='24' />" + item.Name + "</h3><p>" + item.Title + "</p><a href='#' data-value='" + item.AlertId + "' class='btn btn-success btn-sm alertInfo' data-toggle='modal' data-target='#alertDetails'>Details</a></div>";
marker.bindPopup(content);
markers.addLayer(marker);
return marker;
});
map.addLayer(markers); //add the markers to the map
// If both 'markers_array' and 'markers' are needed later, then bundle them into an object.
// If not, then simply return one or other of those variables.
return {
'markers_array': markers_array,
'markers': markers
};
});
}
The detail will need checking, but the overall pattern should be correct.
Upvotes: 1