How to properly populate HTML table with JQuery AJAX using JSON formatted data?

Good afternoon my friends:

I have the following JSON data that is returned from a WCF RESTful Service.

JSON Data:

{"Cities":["LUSAKA","HARARE"],"Countries":["ZAMBIA","ZIMBABWE"]}

As illustrated, the data contains a list of Countries and Cities.

I am attempting to populate an HTML Table with this data.

HTML Table

<table id="location" border='1'>
    <tr>
        <th>Countries</th>
         <th>Cities</th>
    </tr>
</table>

JQuery:
(The below code works, however, it relies on the index of either the Countries or the Cities and i cannot access the data from the item variable in the function:

    var trHTML = '';
            
    $.each(data.Countries, function (i, item) {
        
        trHTML += '<tr><td>' + data.Countries[i] + '</td><td>' + data.Cities[i] + '</td></tr>';
    });
    
    $('#location').append(trHTML);

Finally, I also tried the below code but this does not work:

    $.each(data.d.results,function(d,results){ 
 
        $("#location tbody").append(
                    "<tr>"
                      +"<td>"+results.Countries+"</td>"
                      +"<td>"+results.Cities+"</td>"
                    +"</tr>" )
                })

Here is the complete working code:

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>WCF Client</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

</head>

<body>

<table id="location" border='1'>
    <tr>
        <th>Countries</th>
         <th>Cities</th>
    </tr>
</table>

<script>

var service = 'http://localhost/DistributedDataSystem/Service.svc/';

$(document).ready(function(){

    jQuery.support.cors = true;

    $.ajax(
    {
        type: "GET",
        url: service + '/GetAllCountries/',
        data: "{}",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        cache: false,
        success: function (data) {
            
        var trHTML = '';
                
        $.each(data.Countries, function (i, item) {
            
            trHTML += '<tr><td>' + data.Countries[i] + '</td><td>' + data.Cities[i] + '</td></tr>';
        });
        
        $('#location').append(trHTML);
        
        },
        
        error: function (msg) {
            
            alert(msg.responseText);
        }
    });
})

</script>

</body>
</html>

Is there is better more robust way to do this? For example: I am not certain as to why I am unable to access the data using the item variable in the loop function above.

In regard to the following data:

{"Cities":["LUSAKA","HARARE"],"Countries":["ZAMBIA","ZIMBABWE"]}

What do you mean by the item variable?

It seems to work for me when I replace the country index with the item, for example:

var trHTML = '';

$.each(data.Countries, function (i, item) {
    trHTML += '<tr><td>' + item + '</td><td>' + data.Cities[i] + '</td></tr>';
});

$('#location').append(trHTML);

By the way, you can also use map and join instead of appending to a variable.

$('#location').append(
    $.map(data.Countries, function (item, index) {
    	return '<tr><td>' + item + '</td><td>' + data.Cities[index] + '</td></tr>';
}).join());

Which, instead of using item, is easier to understand when we rename item to country:

$('#location').append(
    $.map(data.Countries, function (country, index) {
    	return '<tr><td>' + country + '</td><td>' + data.Cities[index] + '</td></tr>';
}).join());

Thank you so much Paul! I really appreciate your help and input.

Not a problem. I just realised that having country and data.cities[index] can also raise some questions. You can make this more internally consistent by ignoring the first parameter and using a consistent reference to the array instead.

$('#location').append(
    $.map(data.Countries, function (ignore, index) {
        return '<tr><td>' + data.Countries[index] + '</td><td>' + data.Cities[index] + '</td></tr>';
    }).join()
);

And the reason for the term 'ignore' is as a placeholder, so we can get the index variable. Calling it ignore also allows code linters such as jsLint to know that they shouldn't complain about an unused variable.

It all depends on what you consider to be more important.

Another approach is to move parts such as the row creation code out to a separate function, and even the function that us used by map to create the countries and cities row:

function createTableRow(cells) {
    var tds = cells.map(function (cellContent) {
        return '<td>' + cellContent + '</td>';
    }).join('');
    return '<tr>' + tds + '</tr>';
}
var countriesAndCitiesRow = function (ignore, index) {
    return createTableRow([
        data.Countries[index],
        data.Cities[index]
    ]);
};
$('#location').append(
    $.map(data.Countries, countriesAndCitiesRow)
);

This ends up with us being easily able to see that the location is made by mapping the countries to the countriesAndCitiesRow function, and the rest can be easily followed from there.

As Uncle Bob says when it comes to improving your code, extract till you drop.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.