2

I'm new to AngularJS (and very rusty with javascript) and I can't get this seemingly straightforward action to work.

I have a GeoJSON response from a Django Rest Framework backend as follows (relevant bit only):

{
    "type": "FeatureCollection", 
    "features": [
        {
            "id": 12, 
            "type": "Feature", 
            "geometry": {
                "id": 11, 
                "type": "Feature", 
                "geometry": {
                    "type": "Point", 
                    "coordinates": [
                        -1.54392242410118, 
                        53.797843696134585
                    ]

I want to get the coordinates to pass to Leaflet either directly or via angular-leaflet-directive to display a simple map with a marker at the centre. I have window.MY_SCOPE set to view the contents of $scope in the console and can access the coordinates using data.features[0].geometry.geometry['coordinates'] and this will display in a browser as text but I can't seem to pass it to an embedded Leaflet script (and it's very unwieldy as a variable), and I work out how to extract the values, either as an array or as pair of variable in an external script. Using a loop seems to be the answer although the query will only return one record and I can't get a loop (or two) to return the coordinates. I've been stuck on this for a while now and can't find an example that matches the situation. I have control of the backend so I can change the output if necessary. Does anyone have any insights into this?

EDIT: as answered by @iH8, I'm not returning valid GeoJSON, in the first instance as it had nested geometries, which I have fixed, but also because I am trying to deliver other information with the GeoJSON data as properties, which doesn't validate.

The answer on the DRF side is that I have nested serializers to include the GeoJSON in the data response using django-rest-framework-gis and having both serializers using GeoFeatureModelSerializer, which creates the nested output below. Changing the model with the property information to GeoModelSerializer presents the geo component as a feature and its associated data as properties but not the nested model. I'll spend a bit of time trying to turn it into a valid GeoJSON object but the answer could ultimately to make multiple requests for the page data, which isn't optimal but may be the simplest solution.

UPDATE: after two weeks of head scratching I have managed to get valid geojson from my queryset using by defining values and using django-geojson's serializer. It isn't pretty but it works. However, trying to extract coordinates in an angular controller still doesn't work.

I've boiled my code down to this:

data = {"crs": {"type": "link", "properties": {"href":     "http://spatialreference.org/ref/epsg/4326/", "type": "proj4"}}, "type": "FeatureCollection", "features": [{"geometry": {"type": "Point", "coordinates": [-1.54392242410118, 53.797843696134585]}, "type": "Feature", "properties": {"market_manager__mgt_name": "Leeds Markets", "name": "Leeds Artsmix @ Albion Place", "url": "http://www.artsmix.co.uk/", "contact_email": "marketsmanager@artsmix.co.uk", "schedule__rrule": null, "id": 12}}]};

var coords = data.features[0].geometry.coordinates;

var lat = coords[1];
var lng = coords[0];

and this returns correctly as shown in this Plunk: http://plnkr.co/edit/xunAg5?p=preview

but always fails in an angular controller with the error 'Cannot read property '0' of undefined'. The 'data' object can be queried in the console as can $scope.data. There are a couple of similar questions that suggest that data.features[0] is undefined but I don't understand how it shows correctly in the console and in ng-inspector.

Simon Greenwood
  • 161
  • 1
  • 7

2 Answers2

2

That's not valid GeoJSON. You can verify here: http://www.geojsonlint.com/ A valid GeoJSON collection would look something like this:

{
    "type": "FeatureCollection", 
    "features": [{
        "type": "Feature",
        "properties": {
            "id": 12
        },
        "geometry": {
            "type": "Point", 
            "coordinates": [
                -1.54392242410118, 
                53.797843696134585
            ]
        }
    }, {
        // Another feature
    }]
}

When using a valid featurecollection you would have no problem using either Leaflet's L.GeoJSON layer itself, or the directive's geojson attribute.

Leaflet GeoJSON example: http://leafletjs.com/examples/geojson.html

Leaflet GeoJSON reference: http://leafletjs.com/reference.html#geojson

Angular-leaflet-directive GeoJSON example: http://tombatossals.github.io/angular-leaflet-directive/examples/geojson-example.html

If you want to use the current structure you have you'll need:

data.features[0].geometry.geometry['coordinates'][0] as your longitude data.features[0].geometry.geometry['coordinates'][1] as your latitude

GeoJSON spec:

A position is represented by an array of numbers. There must be at least two elements, and may be more. The order of elements must follow x, y, z order (easting, northing, altitude for coordinates in a projected coordinate reference system, or longitude, latitude, altitude for coordinates in a geographic coordinate reference system).

iH8
  • 27,722
  • 4
  • 67
  • 76
  • The document is complete, I just pasted that in as an illustration. I can extract other fields with no problem. What might have a bearing is that the document isn't just a feature collection but a combination of other database tables, and the main thing is that I can't see a way to set the map centre from the coordinates as they are given unless that's set by default. – Simon Greenwood Feb 09 '15 at 23:18
  • What i was saying is that the feature you're showing there, isn't a valid feature. You can't have a geometry embedded in another geometry. Check the difference between the feature you've got and the one i posted. If you don't believe me, here's the spec: http://geojson.org/geojson-spec.html – iH8 Feb 09 '15 at 23:36
  • I've added a way to grab your coordinates, but i'de really recommend using proper geojson to start with. makes thing much easier. – iH8 Feb 09 '15 at 23:56
  • Ah, got you. You're right, the nested geometries puzzled me. I'll go back to the back end and try and clean it up. Thanks for the clarification on retrieving the coordinates as well, I'd almost got there but couldn't quite get the last part. – Simon Greenwood Feb 10 '15 at 08:08
0

I think I can close this off now, the issue, as I worked out while I was editing this, was that $response doesn't get resolved in the controller so while the query was happening, there wasn't data in the response at that point so it would always appear as undefined. The resolution has been to add a 'resolve' property to the route as per http://www.jvandemo.com/how-to-resolve-angularjs-resources-with-ui-router/. I'm still trying to work out how to get data from the child scope but I've got past the issue of having data in the first place.

Simon Greenwood
  • 161
  • 1
  • 7