8
votes

I am currently placing markers with popups on a leaflet maps as follows:

L.marker([33.767675, -84.537291], {icon:orangeIcon}).addTo(map).bindPopup("a bunch of dynamic html content for the popup window");

I have many markers, with lots of popup content, so in order to speed up my map rendering/page loading I would like to populate the actual popup with URL-based content, but only when that marker is clicked.

Any ideas on how this can be done?

I did find this example (via https://github.com/Leaflet/Leaflet/issues/947) , but my popup just stays at "loading..." and never seems to load the url:

    var marker = L.marker([33.767675, -84.537291]).addTo(map);
    marker.bindPopup("Loading...");

    marker.on('click', function(e) {
            var popup = e.target.getPopup();
            var url="http://www.someurl.com/file.html";
            $.get(url).done(function(data) {
                popup.setContent(data);
                popup.update();
                });
            });

In thinking maybe the .get method should be .ajax , I tried this...but still no dice:

    var marker = L.marker([33.767675, -84.537291]).addTo(map);
    marker.bindPopup("Loading...");

    function onMapClick(e) {
            var popup = e.target.getPopup();
            var url="http://www.r-stop.com";

            $.ajax({ 
                url:"http://www.r-stop.com/index.html"
            }).done(function( data ) {
                popup.setContent( data );
                popup.update();

                });

            };

    marker.on('click', onMapClick );

So...EDIT.... the below code works, but returns the .fail function. Seems there is something up with my $.ajax request. The popup is populated with 'FAIL: [object OBJECT]'

    var marker = L.marker([33.767675, -84.537291]).addTo(map);
    marker.bindPopup("Loading...");

    function onMapClick(e) {
            var popup = e.target.getPopup();


            $.ajax({
                url: "myfile.html",
                })
                .done(function( data ) {
                    popup.setContent( data );
                    popup.update();
                    })
                .fail(function( data ) {
                    popup.setContent( 'FAIL: ' + data );
                    popup.update();
                    });
            };

    marker.on('click', onMapClick );
2

2 Answers

4
votes

The issue was infact with the URL I was calling with the ajax request. The below works:

    var marker = L.marker([33.767675, -84.537291]).addTo(map);
    marker.bindPopup("Loading...");

    function onMapClick(e) {
            var popup = e.target.getPopup();


            $.ajax({
                url: "myurl.html",
                })
                .done(function( data ) {
                    alert( data );
                    popup.setContent( data );
                    popup.update();
                    })
                .fail(function( data ) {
                    alert( 'FAIL: ' + data );

                    });
            };

    marker.on('click', onMapClick );
2
votes

The way I've done this in the past is to create a dummy popup after the click, just before the AJAX request is made. Then, once the request completes, close the placeholder, bind the real popup and open that.

I don't know how (or even if) it would work for a simple marker object like you're describing, as I've only ever tried it in conjunction with L.geoJson layers. The handy thing about that method is that it gives you access to onEachFeature, which lets you call functions to style things dynamically based on the properties of the geoJSON object.

But of course, if you have many markers that need to access many different URLs, you will probably want to put them into a GeoJSON database anyway. Something like this:

var markerdata = {
"type": "FeatureCollection",
    "features": [{
    "type": "Feature",
        "geometry": {
        "type": "Point",
            "coordinates": [-84.537291, 33.767675, 0]
    },
        "properties": {
        "geometry": "Point",
            "name": "Test Marker 1",
            "url": "http://www.someurl.com/file_1.html"
    }
}, {
    "type": "Feature",
        "geometry": {
        "type": "Point",
            "coordinates": [-84.556685, 33.748580, 0]
    },
        "properties": {
        "geometry": "Point",
            "name": "Test Marker 2",
            "url": "http://www.someotherurl.com/file_2.html"
    }
}]
};

To actually bind the popups, the function would look like this:

function onEachMarker(feature, layer) {

layer.on('click', function (e) {
    //destroy any old popups that might be attached
    if (layer._popup != undefined) {
        layer.unbindPopup();
    }
        var marker_url = feature.properties.url;

        //display a placeholder popup
        var pop = L.popup().setLatLng(this._latlng).setContent('Loading...').openOn(map);

        //request data and make a new popup when it's done
        $.ajax({
            url: marker_url,
            success: function (data) {
                    //close placeholder popup
                    layer.closePopup();

                    //attach the real popup and open it
                    layer.bindPopup(data);
                });
                layer.openPopup();
            }
        });
    });
}

Then you can use onEachFeature to call the function for each feature:

//display markers on map
datalayer = L.geoJson(markerdata, {
    onEachFeature: onEachMarker
}).addTo(map);

You can see this method working in a functioning (though slightly different) fiddle here. This sends an AJAX request to the tumblr API each time a marker is clicked and extracts URLs for thumbnail images based on post IDs contained in the geoJSON.

If you still can't get it to work, you should check to see what (if anything) your .get or .ajax requests are returning, via console.log or whatever debugging means you have at your disposal. It's possible that the server is denying your request or that Leaflet just can't understand the data that's being returned.