[GIS] leaflet: javascript scope issue within geojson onEachFeature function

asyncjavascriptleafletweb-mapping

I'm new to javascript and even newer to Leaflet (version 0.7.7), so I'm having difficulty determining how to ask this question.

With leaflet, when I click on a polygon, an ajax request is made, it is converted to geojson, and a popup appears on the map with some of the returned data. On the leaflet website, the example to do such a thing involves using the onEachFeature event of the geoJson method.

However, when I'm inside of the function called by onEachFeature, I can't access any variables outside of that function. In the example below, in the neighborhood_popup, I'd like to be able to access the data in the ajax response.

How can I access data outside of this onEachFeature function? See comments in the example below.

var map = L.map('map').setView([y, x], 11);

// add some other map features here.

var _neighborhood_lookup;
function neighborhood_lookup(latlng) {
    /* do an ajax request to get geojson data */
    var neighborhood_url="/path/to/api/url?lat=" + latlng.lat + "&long=" + latlng.lng;
    var jqxhr = $.get(neighborhood_url, function(res) {
        _neighborhood_lookup = res
        var popup = L.popup({maxWidth:400});
        var style = {}

        function neighborhood_popup(feature, layer) {
            popup.setLatLng(latlng);
            var place = feature.properties;

            /* THIS IS THE PROBLEM I'M HAVING
               I'm trying to get more information out of 
               _neighborhood_lookup at this location, which 
               is an ajax response. However, the _neighborhood_lookup
               is undefined at this point.  How do I access variables
               outside of this function scope? 
            */

            /* this part doesn't really matter for this question,
               but it's gathering variables and rendering them 
               in a handlebars template */
            var context = {
                name: place.name,
                long_name: place.long_name,
            };
            var html = popup_template(context);  
            // sets popup content 
            popup.setContent(html);

        }

        // I think this determines what leaflet feature was clicked
        var neighborhood_layer = L.geoJson(_neighborhood_lookup.neighborhood, {
            style: style,
            onEachFeature: neighborhood_popup
        });

        layergroup.clearLayers();
        layergroup.addLayer(neighborhood_layer);
        map.openPopup(popup);
    })
}

/* when a polygon an the map is clicked,
   we call the neighborhood_lookup function */
map.on('click', function(e) {
  neighborhood_lookup(e.latlng);
});

Update: Here is the json that comes in via the ajax request.


{"neighborhood":
{"id":"108","type":"Feature","geometry":
{"type":"Polygon","coordinates":
[[[-87.684152,41.971901],[-87.684148,41.971794],
[-87.684146,41.971748],[-87.684143,41.971665],
...
[-87.684159,41.972107],[-87.684156,41.972037],
[-87.684154,41.971967],[-87.684152,41.971901]]]
},
"properties": {"created":"2016-06-19T21:50:35.060937Z",
"modified":"2016-0619T21:50:35.060967Z",
"active":true, "name":"108",
"uuid":"1d6162af-2202-40a4-8f1a-697e266a07b9",
"long_name":"Lincoln Square","stats": {}
}
}
}

Best Answer

There were a few things wrong in there, but I think I have a simplified example that will show you want you need to know. The short answer is that on the onEachFeature: neighborhood_popup line, you should put a function there, and then all the function you want to call, passing any data that you want to pass additionally:

code example

Here is the full working code example: https://jsfiddle.net/gavinr/23yu6ooz/