benj
benj

Reputation: 133

Format complex nested objects

I have posted previously in the gis forum (Alt below) though there is little activity so i am trying my luck here. This is also, fundamentally i think, a js object array question. There are numerous similar questions but i just can't get a solution that works for the object structure i have to deal with.

Caveats aside;

The issue: Get the information returned from a (unknown) number of objects nested within an object array parsed so they can be extracted, formatted and displayed in a human readable way. E.g;

Layer id  <--- currently returned as val.layer.id (see snippet)
key1 : value1 <
key2 : value2 <-- returns in console.log as Object at val.properties
key3 : value3 <

Layer id
key1 : value1
key2 : value2

Layer id...

I just need each 'features.layer.id' with it's associated 'features.properties', the keys and values of which are unknown and differ between layers (an object located at features.properties). These feature positions are consistent in MapBox and so a solution here should be applicable to future users.

Current code; Commented out are a scattering of my attempts to access and display the required values. The 'features' elementID is the info panel. features is otherwise the returned nested object (see sample).

concattedjson currently produced an error ("unexpected token N") on first letter of first layer title.

map.on('click', function (e) {
    map.featuresAt(e.point, {radius: 5, layer: lyrlist}, function (err, features) {
        if (err) throw err;

        var keys = Object.keys(features);
        var val = "";

        for (var i = 0; i < keys.length; i++) {
            val = features[keys[i]];
            //document.getElementById('features').innerHTML = '<b>'+val.layer.id+'</b>';
            //console.log(val.layer.id,val.properties);
            //console.log(val.properties); shows each layer properties on click
            //console.log(val.layer.id); shows each layer title on click
            //console.log(val);
            var lyrid = val.layer.id;
            var prop = val.properties;
            concattedjson = JSON.stringify(JSON.parse(lyrid).concat(JSON.parse(prop)));
        }   
    document.getElementById('features').innerHTML = concattedjson   
    //document.getElementById('features').innerHTML = JSON.stringify(val.layer, ['id'], 2);     
    //document.getElementById('features').innerHTML = JSON.stringify(val.properties, null, 2);          
    });
});

Sample of JSON containing two 'layers'

    [
  {
    "layer": {
      "id": "Nature Improvement Area",
      "minzoom": 7,
      "interactive": true,
      "paint": {
        "fill-opacity": 0.3,
        "fill-color": "hsl(0, 24%, 24%)"
      },
      "type": "fill",
      "source": "mapbox://mbbdev.8uf2j3ka",
      "source-layer": "lcr_nia_v1_region",
      "layout": {
        "visibility": "visible"
      }
    },
    "type": "Feature",
    "geometry": null,
    "properties": {
      "NIA_Focu00": "Netherley Brook and Ditton Brook Corridor",
      "NIA_Focu01": "INSERT LINK TO PROFILE DOC",
      "NIA_Focus_": "07"
    },
    "id": 16
  },
  {
    "layer": {
      "id": "Liverpool City Region",
      "minzoom": 6,
      "interactive": true,
      "paint": {
        "fill-opacity": 0.2,
        "fill-antialias": true,
        "fill-color": "hsl(0, 4%, 40%)"
      },
      "type": "fill",
      "source": "mapbox://mbbdev.67id5f6x",
      "source-layer": "lcr_district_boundary_region",
      "filter": [
        "==",
        "$type",
        "Polygon"
      ]
    },
    "type": "Feature",
    "geometry": null,
    "properties": {
      "AREA_HA": 8618.7,
      "NAME": "Knowsley"
    },
    "id": 1
  }
]

Upvotes: 2

Views: 4413

Answers (1)

iH8
iH8

Reputation: 28638

Here's how you iterate the features object, and create something human readable out of it. Explanation in the comments:

map.on('click', function (e) {
    map.featuresAt(e.point, {
        radius: 5,
    }, function (err, features) {
        if (err) throw err;

        // Grab the 'ul' element with ID 'features' from the DOM            
        var featureList = document.getElementById('features');

        // Empty the list on every click
        featureList.innerHTML = '';

        // Iterate the features array
        for (var i = 0; i < features.length; i++) {

            // Create a listitem for each feature
            var featureItem = document.createElement('li');

            // Set the feature's listitem's content to the layer's ID
            featureItem.textContent = features[i].layer.id;

            // Append the featureitem to the featurelist
            featureList.appendChild(featureItem);

            // Create a new list for the item's properties
            var propertyList = document.createElement('ul');

            // Append the list to the feature's listitem
            featureItem.appendChild(propertyList);

            // Create convenience var for the properties object
            var properties = features[i].properties;

            // Iterate the properties object
            for (var property in properties) {

                // Create new listitem for every property
                var propertyItem = document.createElement('li');

                // Set property's listitem's textcontent to key/value
                propertyItem.textContent = property + ': ' + properties[property];

                // Append property's listitem to the feature's propertylist.
                propertyList.appendChild(propertyItem);

            }

        }

    });
});

Here's a working example on Plunker: http://plnkr.co/edit/iqntvRFTcWK1hgpzPBvX?p=preview

You might want to read this if you want to grasp the concept of object properties and how to access them:

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors

Upvotes: 3

Related Questions