1
\$\begingroup\$

I'm displaying JSON data in a tabular format on a html page using jQuery.

In the function I'm looping the resp.DATA once to get the key names so it can be displayed as the headings in the table, and a second time to get the values of the keys for all customers.

Can this be done in a way that I only have to loop the resp.DATA once?

JSON data:

    var resp= {
    "ERROR": [],
    "DATA": [{
        "CustomerID": "234",
        "BranchID": "1",
        "LocationID": "26",
        "FirstName": "Lakshmi "
    }, {
        "CustomerID": "235",
        "BranchID": "1",
        "LocationID": "6",
        "FirstName": "Arora "
    }, {
        "CustomerID": "236",
        "BranchID": "1",
        "LocationID": "68",
        "FirstName": "S.K.Raman "
    }, {
        "CustomerID": "237",
        "BranchID": "1",
        "LocationID": "38",
        "FirstName": "Vidya Rao "
    }, {
        "CustomerID": "238",
        "BranchID": "1",
        "LocationID": "18",
        "FirstName": "Raju "
    }, {
        "CustomerID": "239",
        "BranchID": "1",
        "LocationID": "49",
        "FirstName": "K.B.Hebbar "
    }],
    "META": {
        "currentPageNumber": "1",
        "totalPages": "11",
        "rowcountCurrentPage": "10",
        "rowcountTotal": "107"
    }
}

Code:

            var content = '<table class="table table-hover">';
            var heading = "<tr>";
            var data = "";
            $.each(resp.DATA[0], function(ke, va) {
                heading += '<th>' + ke + '</th>';
            });
            $.each(resp.DATA, function(key, value) { 

                data += "<tr>";
                $.each(value, function(k, v) {
                   data += '<td>' + v + '</td>';
                });
                data += "</tr>";
            });
            heading += "</tr>";
           content += heading + data + "</table>";
            $('#data').append(content);

HTML file:

<!DOCTYPE html>
<html>
<head>
    <title>COnsuming rest webservice</title>
    <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> </head>
<body>
    <h1>Consuming REST api</h1>
    <div class="container">
        <div id="data"> </div>
    </div>
    <!-- <input type="button" id="driver" value="Load Data" /> -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
    <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
    </script>
</body>
</html>

You can see a working example here.

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

You may take advantage of reduce() and map() functions to have no loop at all, like this:

$('#data').append(
  resp.DATA.reduce((table, obj, index) => (
    table + (
      !index ? (
        Object.keys(obj).reduce((header, key) => `${header}<th>${key}`, '<tr>')
      ) : ''
    ) + $.map(obj, v => v).reduce((row, value) => `${row}<td>${value}`, '<tr>')
  ), '<table class="table table-hover">') + '</table>'
);

I also used some tagged strings, so more reducing the size of the code.
Additionally it works a bit faster than the original version, as you can observe with the following snippet.

var resp= {
  "ERROR": [],
  "DATA": [{
    "CustomerID": "234",
    "BranchID": "1",
    "LocationID": "26",
    "FirstName": "Lakshmi "
  }, {
    "CustomerID": "235",
    "BranchID": "1",
    "LocationID": "6",
    "FirstName": "Arora "
  }, {
    "CustomerID": "236",
    "BranchID": "1",
    "LocationID": "68",
    "FirstName": "S.K.Raman "
  }, {
    "CustomerID": "237",
    "BranchID": "1",
    "LocationID": "38",
    "FirstName": "Vidya Rao "
  }, {
    "CustomerID": "238",
    "BranchID": "1",
    "LocationID": "18",
    "FirstName": "Raju "
  }, {
    "CustomerID": "239",
    "BranchID": "1",
    "LocationID": "49",
    "FirstName": "K.B.Hebbar "
  }],
  "META": {
    "currentPageNumber": "1",
    "totalPages": "11",
    "rowcountCurrentPage": "10",
    "rowcountTotal": "107"
  }
}

var begTime = performance.now();var content = '<table class="table table-hover">';
var heading = "<tr>";
var data = "";
$.each(resp.DATA[0], function(ke, va) {
  heading += '<th>' + ke + '</th>';
});
$.each(resp.DATA, function(key, value) { 
  data += "<tr>";
  $.each(value, function(k, v) {
    data += '<td>' + v + '</td>';
  });
  data += "</tr>";
});
heading += "</tr>";
content += heading + data + "</table>";
$('#data').append(content);
$('#data').append(`<h3>OLD: ${performance.now() - begTime} ms</h3>`);

var begTime = performance.now();
$('#data').append(
  resp.DATA.reduce((table, obj, index) => (
    table + (
      !index ? (
        Object.keys(obj).reduce((header, key) => `${header}<th>${key}`, '<tr>')
      ) : ''
    ) + $.map(obj, v => v).reduce((row, value) => `${row}<td>${value}`, '<tr>')
  ), '<table class="table table-hover">') + '</table>'
);

$('#data').append(`<h3>NEW: ${performance.now() - begTime} ms</h3>`);
<!DOCTYPE html>
<html>
<head>
    <title>COnsuming rest webservice</title>
    <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> </head>
<body>
    <h1>Consuming REST api</h1>
    <div class="container">
        <div id="data"> </div>
    </div>
    <!-- <input type="button" id="driver" value="Load Data" /> -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
    <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
    </script>
</body>
</html>

NOTE: in your version as well as mine, we never take care of the keys in nested objects: they work only if they appear always in the same order!

\$\endgroup\$
0
\$\begingroup\$

try this one.i didn't test but hope it will work. You can replace search method to contains or indexof whatever..

var heading = "<tr>";
$.each(resp.DATA, function(key, value) { 

             data += "<tr>";
             $.each(value, function(k, v) {

           if(heading.search( k ) == -1)//allow key not found in existing value
                   heading += '<th>' + k + '</th>';

                   data += '<td>' + v + '</td>';
             });
             data += "</tr>";
 });

Finally append your strings

heading += "</tr>";
content += heading + data + "</table>";
$('#data').append(content);

2)
var headingArr=[];
    $.each(resp.DATA, function(key, value) { 

                 data += "<tr>";
                 $.each(value, function(k, v) {


                       heading.push('<th>' + k + '</th>');

                       data += '<td>' + v + '</td>';
                 });
                 data += "</tr>";
     });

remove duplicates using unique from headingArr array and convert array to string.after append it to ur html element.
\$\endgroup\$
2
  • \$\begingroup\$ code is working fine but in this code also the ` if(heading.search( k ) == -1)` will be executed many times i,e even when we get all the headings it will check No. of headings* No of k . This will be time consuming as the data iam applying this code is huge.. Thanks for ur response any help will be thankful. \$\endgroup\$
    – Sandeep
    Commented Feb 3, 2016 at 11:01
  • \$\begingroup\$ @Sandeep plz check my another answer. \$\endgroup\$
    – Dharma
    Commented Feb 3, 2016 at 11:20

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.