ufollettu
ufollettu

Reputation: 882

jQuery Array.map and Object.keys() to map key of an array of object

I have a JSON file here: https://next.json-generator.com/api/json/get/E1qcwkNxr

and I want to use it to create a table. Using jQuery I get the response Array and map some values to build my table body cells:

        var data = $.getJSON('https://next.json-generator.com/api/json/get/E1qcwkNxr', function (response) {

            // map JSON to local arrays and define local vars
            var rows = response.map(function (r) {
                return [
                    r.age,
                    r.index,
                    r.registered,
                    r.balance,
                    r.eyeColor
                ];
            });
        });

I want to do the same thing with the keys because I want to build the thead cells with that data. There's a way to do it? Object.keys(response[0]); log me all the keys in the object, How can I map only the key I want to use?

Upvotes: 0

Views: 2894

Answers (2)

Twisty
Twisty

Reputation: 30893

I would suggest you use $.each() and not $.map(). Something like this:

var rows = [];
$.getJSON('https://next.json-generator.com/api/json/get/E1qcwkNxr', function (response) {
  $.each(response, function(i, x){
    var obj = {};
    var s = ["age", "index", "registered", "balance", "eyeColor"];
    $.each(x, function(k, v){
      if(s.indexOf(k) >= 0){
        obj[k] = v;
      }
    });
    rows.push(obj);
  });
});

Now you will have a clean array of Objects that has both Keys and Values. You can then use it to build your table.

var $table = $("<table>");
$("<thead>").appendTo($table);
$("<tr>").appendTo($("thead", $table));
$.each(rows[0], function(key, val){
  $("<th>").html(key).appendTo($("thead tr", $table));
});
var $tbody = $("<tbody>").appendTo($table);
$.each(rows, function(ind, row){
  var $trow = $("<tr>").appendTo($tbody);
  $.each(row, function (item){
    $("<td>").html(item).appendTo($trow);
  });
});

Working Example: https://jsfiddle.net/Twisty/xv4kzy8L/

Update

If you need the the table to display in a specific sort, you can do this with your Array of key names. Then display the results in a specific order:

var headers = ["age", "index", "registered", "balance", "eyeColor"];
var $table = $("<table>");
$("<thead>").appendTo($table);
$("<tr>").appendTo($("thead", $table));
$.each(headers, function(key, val){
  $("<th>").html(val).appendTo($("thead tr", $table));
});
var $tbody = $("<tbody>").appendTo($table);
$.each(rows, function(ind, row){
  var $trow = $("<tr>").appendTo($tbody);
  $.each(headers, function (k, i){
    $("<td>").html(row[i]).appendTo($trow);
  });
});

Hope that helps.

Upvotes: 0

Jack
Jack

Reputation: 9388

To answer your question regarding Object.keys, you would need to filter against a known set.

For example:

let keysToRender = ['index', 'age'];
Object.keys(response[0]).filter(key => { return ~keysToRender.indexOf(key) })

Here's a solution I threw together (it's based on the fiddle link I posted in my comments to you, but cleaned up) which uses map. Personally, I prefer map over $.each (for this problem) as there's slightly less overhead.

Fiddle: http://jsfiddle.net/x3p79jfs/

Edit: Here's a fiddle that maintains order based on response (as you mentioned in the other comment) - http://jsfiddle.net/x3p79jfs/1/

Hope it helps!

$.getJSON('https://next.json-generator.com/api/json/get/E1qcwkNxr', function(res) {
    // Extracts values from response
    const getModelFromKeys = (res, keys) => {
        return res.map(item => {
            return keys.map(key => {
                return item[key];
            });
        });
    };

    // Build template to append
    const buildTableFromModel = (header, body) => {
        let reducer = (arr, func, acc) => {
            return arr.reduce(func, acc);
        };

        let getTemplateCell = (template, item) => template + `<td>${item}</td>`;
        let getTemplateRow = (template, item) => template + `<tr>${reducer(item, getTemplateCell, ``)}</tr>`;
        
        return `
            <table><thead><tr>
            ${reducer(header, getTemplateCell, ``)}
            </tr></thead><tbody>
            ${reducer(body, getTemplateRow, ``)}
            </tbody></table>
        `
    };

    // Our expected set of keys to render (note first, last names which do not exist)
    let pii_table = ['age', 'index', 'first_name', 'last_name', 'registered', 'balance', 'eyeColor'];

    // Filter expected keys against ajax response
    // let filteredKeys = Object.keys(res[0]).filter(key => {
    //    return ~pii_table.indexOf(key);
    // });

    // Filter expected keys against ajax response
    let responseKeys = Object.keys(res[0]);
    let filteredKeys = pii_table.filter(key => {
        return ~responseKeys.indexOf(key);
    });

    // Build Table Model From Filtered Keys
    let firstTableModel = getModelFromKeys(res, filteredKeys);
    
    // Append table to Body
    document.body.innerHTML += buildTableFromModel(filteredKeys, firstTableModel);
});
td {
    padding: 3px;
    text-align: center;
}
thead {
    color: white;
    background-color: #777;
}
tr:nth-child(2n) {
    background-color: #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Upvotes: 1

Related Questions