Remove columns in HTML table where the sum is 0

Posted on

Problem

I have an HTML table, and I would like to remove columns where the sum vertically is 0 dynamically.

Four-column table, with a header row followed by three rows of integers

let ths_columns = [...document.querySelectorAll("thead tr th")].map(
  (th) => th.textContent.trim()
); //first row of table header [ "column_1", "column_2", "column_3", "column_4" ]
let trs = [...document.querySelectorAll("tbody tr")]; // three rows of table tbody [ tr, tr, tr ]
//convert table into 2d-array dimension  like matrix: trs_rows [[[10, 0, 5, 0]], [[3, 0, 6, 0]], [[8, 0, 2, 0]]];
const trs_rows = [];
for (let tr of trs) {
  trs_rows.push([[...tr.children].map((td) => +td.textContent)]);
}
//make an array looks like ths_columns contains sum of rows vertically
const ths_rows_result = Array.from({ length: ths_columns.length }).fill(
  0
);
for (let i = 0; i < trs_rows.length; i++) {
  const element = trs_rows[i];
  for (let j = 0; j < element.length; j++) {
    for (let k = 0; k < element[j].length; k++) {
      const td = element[j][k];
      //console.log(td);
      ths_rows_result[k] += td;
    }
  }
}
console.log(ths_rows_result); //  [21, 0, 13, 0]

// make an array which contains name of columns have
const array_zeros = ths_columns
  .map((th, i) => [th, ths_rows_result[i]])
  .filter((entries) => entries[1] == 0)
  .map((entry) => entry[0]);
//console.log(array_zeros); //  ['column_2', 'column_4']

// make the same array but this time contains id instead of column's name
const array_index = [];
for (let i = 0; i < ths_columns.length; i++) {
  const element = ths_columns[i];
  if (array_zeros.includes(element)) {
    array_index.push(i);
  }
}
//console.log(array_index); //[1, 3]

//loop over first row and if a cell is in  add to a cell class none (in css .none{display: none;})
let ths = [...document.querySelectorAll("thead tr th")];
for (let i = 0; i < ths.length; i++) {
  const th = ths[i];
  if (array_index.includes(i)) {
    th.classList.add("none");
  }
}

//loop over other rows and do the same process if a cell is in  add to a cell class none (in css .none{display: none;})
for (let i = 0; i < trs.length; i++) {
  const element = trs[i];
  let tds = [...element.querySelectorAll("td")];
  for (let j = 0; j < tds.length; j++) {
    if (array_index.includes(j)) {
      tds[j].classList.add("none");
    }
  }
}
table {
  border-collapse: collapse;
  border: 1px solid;
}
tr,
th,
td {
  border: 1px solid;
  text-align: center;
}
.none {
  display: none;
}
<table class="table_pp">
  <thead>
    <tr>
      <th>column_1</th>
      <th>column_2</th>
      <th>column_3</th>
      <th>column_4</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>10</td>
      <td>0</td>
      <td>5</td>
      <td>0</td>
    </tr>
    <tr>
      <td>3</td>
      <td>0</td>
      <td>6</td>
      <td>0</td>
    </tr>
    <tr>
      <td>8</td>
      <td>0</td>
      <td>2</td>
      <td>0</td>
    </tr>
  </tbody>
</table>

Is it the right way of doing it?

Solution

Aside from the ambiguity in the question, you are definitely taking a circuitous route to identify the columns. CSS’s nth-child would vastly simplify querying the DOM.

// determine column count from th cells in thead
document.querySelectorAll('thead th').forEach((_, i) => {

  // only interested in the nth-child for each column in the tbody
  const cols = [...document.querySelectorAll(`tbody tr td:nth-child(${i+1})`)]

  // get the sum (or whatever determines why to hide
  const total = cols.reduce((acc, col) => acc + parseInt(col.textContent), 0)

  if (total === 0) {
    // add the css class to each tbody column
    cols.forEach(col => {
      col.classList.add('none')
    })

    // also hide the header th
    const headerCol = document.querySelector(`thead th:nth-child(${i+1})`)
    if (headerCol) headerCol.classList.add('none')
  }
  
})
table {
  border-collapse: collapse;
  border: 1px solid;
}
tr,
th,
td {
  border: 1px solid;
  text-align: center;
}
.none {
  display: none;
}
<table class="table_pp">
  <thead>
    <tr>
      <th>column_1</th>
      <th>column_2</th>
      <th>column_3</th>
      <th>column_4</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>10</td>
      <td>0</td>
      <td>5</td>
      <td>0</td>
    </tr>
    <tr>
      <td>3</td>
      <td>0</td>
      <td>6</td>
      <td>0</td>
    </tr>
    <tr>
      <td>8</td>
      <td>0</td>
      <td>2</td>
      <td>0</td>
    </tr>
  </tbody>
</table>

Leave a Reply

Your email address will not be published. Required fields are marked *