I have an ajax link getting data from GeoServer. When a user selects features on a map, a new bounding box is calculate and sent via Ajax to GeoServer and the features within that bounding box are sent back.

I have a handleJson function for the selected features returned from GeoServer:

        function handleJson(data) {
                    selectedFeature = L.geoJson(data, {

                        onEachFeature: function (feature, layer) {                                            
                        for(name in feature.properties){                         
                                    document.getElementById("properties").innerHTML =                 document.getElementById("properties").innerHTML +
                                    "<tr><td>" + name + "<td>" + feature.properties[name] + "<td>";

                        pointToLayer: function (feature, latlng) {

                            return L.circleMarker(latlng, {
                                radius: 5,
                                color: '#3006e8',
                                weight: 5,
                                opacity: 1,
                                fillOpacity: 1

Currently I can get all of the data back in this format (just plunked right onto the map itself):

Name: George Costanza 
Occupation: Bra Salesman/Kruger Industrial Smoothing
Strengths: Lying 
Weaknesses: He was in the pool.

This is fine if you only have one feature selected, but if you have multiple, it needs to be in a format closer to microsoft excel with rows and columns like this:

Name       Occupation        Strengths      Weaknesses
person1    person1 job    person1 strength person1 weakness
person2    person2 job    person2 strength person2 weakness
person3    person3 job    person3 strength person3 weakness

I have tried various for loops and putting things to arrays, but I cannot get get it to work. forEachFeature just keeps copying what would be the column name (the "key" in the key:value pair). I need the column names set up once and then just get the data associated (the "value" in the key:value pair). Is this possible?


Name: Person Person 
Occupation: Some Job
Strengths: Some Strength 
Weaknesses: Some Weakness
Name: Other Person 
Occupation: Some OTHER Job
Strengths: Some OTHER Strength 
Weaknesses: Some OTHER weakness
Name: Other Person 2
Occupation: sadfsadds
Strengths: Lasdfafffd
Weaknesses: asdasfdsadf
  • It seems like your table tags are not in order, try switching "<tr><td>" + name + "<td>" + feature.properties[name] + "<td>" with ` "<tr><td>" + name + "</td><td>" + feature.properties[name] + "</td></tr>"` (Don't know if it will solve it...) – NettaB Jul 13 '17 at 16:41
  • Still the same output, unfortunately. It stack's everything in the same format, but on top of each other. If I could hit "enter" here I would show you the output. – Marcus Holden Jul 13 '17 at 16:46
  • I'm populating some custom layer attributes in the onEachFeature loop, never tried to build HTML inside. What is "in top of each other means?" did you try writing the values to the console to see if you can get the properties? – NettaB Jul 13 '17 at 16:55
  • I am open to any suggestions on how to piece the table together. I've never done this before. I have updated the question with what currently happens. – Marcus Holden Jul 13 '17 at 17:02
  • So you do get the data, but you don't see in a table - you don't have table tags. Try creating a table element inside #properties and than change the innerHTML of the table element. – NettaB Jul 13 '17 at 17:09

Looking at this as an example for the dynamic table. https://www.aspsnippets.com/Articles/Create-dynamic-Table-in-HTML-at-runtime-using-JavaScript.aspx. I'm using an esri Featurelayer instead of Geoserver but I create an array on the onEachFeature and then use the array to populate the table on button click. Maybe this example will help.

<!DOCTYPE html>


    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!--<link rel="shortcut icon" type="image/x-icon" href="images/favicon.ico" />-->
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.1.0/dist/leaflet.css" integrity="sha512-wcw6ts8Anuw10Mzh9Ytw4pylW8+NAD4ch3lqm9lzAsTxg0GFeJgoAtxuCLREZSC5lUXdVyo/7yfsqFjQ4S+aKw==" crossorigin=""/>
    <script src="https://unpkg.com/leaflet@1.1.0/dist/leaflet.js" integrity="sha512-mNqn2Wg7tSToJhvHcqfzLMU6J4mkOImSPTxVZAdo+lcPlk+GhZmYgACEe0x35K7YzW1zJ7XyJV/TT1MrdXvMcA==" crossorigin=""></script>

     <!-- Load Esri Leaflet from CDN -->
    <script src="https://unpkg.com/esri-leaflet@2.0.3"></script>

height: 400px;


<input type="button" value="Generate Table" onclick="GenerateTable()" />
<hr />
<div id="map"> 
<div id="dvTable">

var map = L.map('map').setView([42.87, -75.0], 7); 

function style3(feature) {      //County
    return {
        fillColor: '#2E8B57',
        fillOpacity: .6,
        weight: 2,
        opacity: 1,
        color: '#ffffff',
        dashArray: '3'

var theCnty = [];
county = L.esri.featureLayer({
        url: 'https://geohealth.hhs.gov/dataaccess/rest/services/CMS_DME/HHS_CMS_DME_ESRD_onlyAll/MapServer/1',
        where: "State = 'NY'",
        outFields:'Name, Medicare_Benes,Power_Dependent_Devices_DME',
        simplifyFactor: 0.5, 
        style: style3,

        onEachFeature: function(feature, layer)

                NAME: feature.properties.NAME,
                DME: feature.properties.Power_Dependent_Devices_DME,
                Med: feature.properties.Medicare_Benes




function GenerateTable() {

     //Create a HTML Table element.
    var table = document.createElement("TABLE");
    table.border = "1";

    //Add the header row.
    var row = table.insertRow(-1);
        var headerCell = document.createElement("TH");
        headerCell.innerHTML = "NAME";  //Fieldname
        var headerCell = document.createElement("TH");
        headerCell.innerHTML = "DME";   //Fieldname
        var headerCell = document.createElement("TH");
        headerCell.innerHTML = "Med";   //Fieldname

    //Add the data rows. 
    for (var i = 0; i < theCnty.length; i++) {
        row = table.insertRow(-1);

            var cell = row.insertCell(-1);
            cell.innerHTML = theCnty[i].NAME;
            var cell = row.insertCell(-1);
            cell.innerHTML = theCnty[i].DME;
            var cell = row.insertCell(-1);
            cell.innerHTML = theCnty[i].Med;


    var dvTable = document.getElementById("dvTable");
    dvTable.innerHTML = "";
  • Thanks! I'm getting this set up now. I'm noticing two things: 1) it's not getting the first element in my rows. The header section works great. The row section though.. if I have 21 elements, it's only putting 20 in the table. It's cutting off the first one. 2) is there a way to set it up so it doesn't keep duplicating the header section if multiple features are selected?? – Marcus Holden Jul 14 '17 at 16:16
  • Actually I had the same thing happen last week, as I was looping through a list of regions, I ended up getting each letter instead of each item. I changed my data to this key:value format to get away from it. I'm not sure what caused it. – Bill Chappell Jul 14 '17 at 16:22
  • Make sure the header row is not in a loop and fix the "for (var i=1" to "for (var i=1" under the //Add the data rows. As 1 it skips the first record, should be 0 for the first record. Sorry, it was an error in the code I referenced and I didn't catch it. – Bill Chappell Jul 14 '17 at 16:28
  • Tunnel vision... I did not even see that var was set to 1. That part works great now! Now I just need to make it so it only creates the column names once and puts all the on their each row (for instance. if there are 21 values it will put the 21 values for the first feature on a row.. then another row for the 21 values of the next feature.. etc.). This has been VERY helpful! – Marcus Holden Jul 14 '17 at 16:36

Ok, try this as an example. I'm using Bootstrap for the table. Notice the table FIELDNAMES are predefined at the bottom of the page. This is also different as I'm using AJAX to hit an ArcServer REST but I'm not using a map so I didn't have to open it into a separate div.

<!DOCTYPE html>
    <title>NY emPOWER County Data</title>
    <script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script> 
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
     <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    body {
        background-color: #B7C3D0;

        text-align: right;
         font-weight: bold;
         color: #00688B;


var arr = [];
var theCnty = [];

var theUrl = "https://geohealth.hhs.gov/dataaccess/rest/services/CMS_DME/HHS_CMS_DME_ESRD_onlyAll/MapServer/1/";

var d = new Date();

    type: "POST",
    url: theUrl + "/query?",
        dataType: "jsonp",
        crossDomain: true,

        data: {
            f: "json",
          //outFields: '*', 
            outFields:'Name, Medicare_Benes,Power_Dependent_Devices_DME',
           returnGeometry: false,
            where: "State='NY' "//AND County in ('Saratoga','Ulster')"


        var data =(JSON.stringify(json));

        processData (json);
            console.log("Error");  //hit F12 in browser to see console.

function processData (obj){
    for (var a = 0; a < obj.features.length; a++) {

            NAME: obj.features[a].attributes.NAME,
            PPD: obj.features[a].attributes.Power_Dependent_Devices_DME,
            Medicare: obj.features[a].attributes.Medicare_Benes

        console.log(theCnty[a].NAME +", " +theCnty[a].Medicare +", " +theCnty[a].PPD);



function plotSubTable(){

document.getElementById("showDate").innerHTML  = d.toDateString();
myTBody = $("#crtable > tbody"); //find the TBody inside your table above (where your TR/TD’s go
    var curTR;
    theCnty.forEach(function(i) {
        console.log(i.NAME + ", " + i.Medicare+ ", " +i.PPD);

         curTR = myTBody.last(); //find the last row in your TBody

        //now simply append a TR to that
        curTR.append('<tr><td>'+i.NAME+'</td>' + '<td>' + i.Medicare.toLocaleString()+ '</td>'+ '<td>' + i.PPD.toLocaleString()+ '</td></tr>');

}  //END plotSubTable

// <tr class="success">  //https://www.w3schools.com/bootstrap/bootstrap_tables.asp

    <div id="results" class="col-sm-6 col-sm-offset-3">

        <div class="panel panel-default">
  <div class="panel-heading"><b>emPOWER NY</b></div>
  <div class="panel-body">       
            <p id="showDate" >Today is:  </p>
            <div class="scrollableTable">

                <table class="table table-bordered table-condensed table-striped table-hover" id="crtable">
                     <thead class="thead-inverse">
                        <tr class="success">
                            <th>Electricity dependent</th>
                    <tbody id="resultsTBody">                        

  • I think the other solution may be closer. I need the table generated to be completely different depending what feature is selected. Click on a person and their info comes up.. then click on a county and it's info comes up.. click on several people and all their info comes up, but the headers are only loaded once. – Marcus Holden Jul 14 '17 at 19:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.