dellavi98
dellavi98

Reputation: 43

Generate a table from array of objects

Ok, so I have an array of objects that look like that

{id: 1, color: "red", size: "S", free: 14, location: "Location #1"}
{id: 2, color: "green", size: "M", free: 5, location: "Location #1"}
{id: 3, color: "red", size: "M", free: 3, location: "Location #2"}
{id: 4, color: "green", size: "L", free: 12, location: "Location #1"}
{id: 5, color: "green", size: "S", free: 5, location: "Location #2"}
{id: 6, color: "red", size: "L", free: 0, location: "Location #1"}
{id: 7, color: "blue", size: "L", free: 0, location: "Location #2"}
{id: 8, color: "blue", size: "M", free: 0, location: "Location #1"}
{id: 9, color: "blue", size: "S", free: 0, location: "Location #1"}
{id: 10, color: "purple", size: "L", free: 0, location: "Location #2"}

And I want to be able to generate a table that would look something like that

enter image description here

I suppose that i have to filter or group some of the key-value pairs or something like that but i don't know the right way to approach this.

Again maybe for this particular table I have to do something like this:

{
  color: 'red',
  location: 'Location #1',
  sizes: [
    {
      s: 12
    },
    {
      m: 5
    },
    {
      l: 7
    }
  ]
}

{
  color: 'green',
  location: 'Location #1',
  sizes: [
    {
      s: 3
    },
    {
      m: 11
    },
    {
      l: 4
    }
  ]
}

But then i have to figure out how to populate the HTML table itself with this data. Maybe there is some library or something that would help me do that. Thanks!

Upvotes: 1

Views: 724

Answers (2)

jo_va
jo_va

Reputation: 13983

See the table generated at the end

You can use reduce to accumulate the sizes for each color and each location. Here is an example way to use reduce and the resulting tree.

const tree = data.reduce((accum, { id, color, size, free, location }) => {
  accum[location] = accum[location] || { };
  accum[location][color] = accum[location][color] || { S: 0, M: 0, L: 0 };
  accum[location][color][size] += free;
  return accum;
}, {});
{
  "Location #1": {
    "red": {
      "S": 14,
      "M": 0,
      "L": 0
    },
    "green": {
      "S": 0,
      "M": 5,
      "L": 12
    },
    "blue": {
      "S": 0,
      "M": 0,
      "L": 0
    }
  },
  "Location #2": {
    "red": {
      "S": 0,
      "M": 3,
      "L": 0
    },
    "green": {
      "S": 5,
      "M": 0,
      "L": 0
    },
    "blue": {
      "S": 0,
      "M": 0,
      "L": 0
    },
    "purple": {
      "S": 0,
      "M": 0,
      "L": 0
    }
  }
}

To create the table, you can iterate over the location entries, and for each location iterate over the colors, then append the rows to the table.

You can create each row by cloning a row template that you query from the DOM, then append that row to your table body:

const data = [  
  {id: 1, color: "red", size: "S", free: 14, location: "Location #1"},
  {id: 2, color: "green", size: "M", free: 5, location: "Location #1"},
  {id: 3, color: "red", size: "M", free: 3, location: "Location #2"},
  {id: 4, color: "green", size: "L", free: 12, location: "Location #1"},
  {id: 5, color: "green", size: "S", free: 5, location: "Location #2"},
  {id: 6, color: "red", size: "L", free: 0, location: "Location #1"},
  {id: 7, color: "blue", size: "L", free: 0, location: "Location #2"},
  {id: 8, color: "blue", size: "M", free: 0, location: "Location #1"},
  {id: 9, color: "blue", size: "S", free: 0, location: "Location #1"},
  {id: 10, color: "purple", size: "L", free: 0, location: "Location #2"}
];

const tree = data.reduce((accum, { id, color, size, free, location }) => {
  accum[location] = accum[location] || { };
  accum[location][color] = accum[location][color] || { S: 0, M: 0, L: 0 };
  accum[location][color][size] += free;
  return accum;
}, {});

const tpl = document.querySelector('#row-template');
const tbody = document.querySelector("tbody");

Object.entries(tree).forEach(([location, values]) => {
  Object.entries(values).forEach(([color, sizes]) => {
    const clone = document.importNode(tpl.content, true);
    const td = clone.querySelectorAll("td");
    td[0].textContent = location;
    td[1].textContent = color;
    td[2].textContent = sizes['S'];
    td[3].textContent = sizes['M'];
    td[4].textContent = sizes['L'];

    tbody.appendChild(clone);
  });
});
table {
  border-collapse: collapse;
}
thead {
  font-weight: bold;
}
td {
  padding: 5px;
  border: 1px solid black;
}
<template id="row-template">
  <tr>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
  </tr>
</template>

<table id="data-table">
  <thead>
    <tr>
      <td>Location</td><td>color</td><td>S</td><td>M</td><td>L</td>
    </tr>
  </thead>
  <tbody>
  </tbody>
</table>

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386868

You could build a tree and collect al value you have in your data set. The result is a tree where the keys are the location, color and size values. At the leaves, you get the accumulated value of free.

Then you could build a array for the table with the accumulated values.

function getTable(object) {
    function getRows(object, row = []) {
        if (row.length === 2) {
            table.push(row.concat(['S', 'M', 'L'].map(k => object[k] || 0)));
            return;
        }
        Object.entries(object).forEach(([k, v]) => getRows(v, row.concat(k)));
    }

    var table = [];
    getRows(object);
    return table;
}

var data = [{ id: 1, color: "red", size: "S", free: 14, location: "Location #1" }, { id: 2, color: "green", size: "M", free: 5, location: "Location #1" }, { id: 3, color: "red", size: "M", free: 3, location: "Location #2" }, { id: 4, color: "green", size: "L", free: 12, location: "Location #1" }, { id: 5, color: "green", size: "S", free: 5, location: "Location #2" }, { id: 6, color: "red", size: "L", free: 0, location: "Location #1" }, { id: 7, color: "blue", size: "L", free: 0, location: "Location #2" }, { id: 8, color: "blue", size: "M", free: 0, location: "Location #1" }, { id: 9, color: "blue", size: "S", free: 0, location: "Location #1" }, { id: 10, color: "purple", size: "L", free: 0, location: "Location #2" }],
    tree = data.reduce((r, o) => {
        var q = ['location', 'color'].reduce((p, k) => p[o[k]] = p[o[k]] || {}, r);
        q[o.size] = (q[o.size] || 0) + o.free;
        return r;
    }, {}),
    table = getTable(tree);

console.log(tree);
console.log(table);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Related Questions