0
\$\begingroup\$

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?

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Do you have control over the HTML representation of the table or not? \$\endgroup\$ Jun 9 at 0:13
  • 1
    \$\begingroup\$ I have no idea why you want to do this, but if the idea is to remove columns that contain nothing but zeros, then your code doesn't work. It does work, if your intend is to remove columns that sum up to zero. See: CodePen. Note that column 2 contains [-1, 0, 1] which totals to zero. \$\endgroup\$ Jun 9 at 8:16

1 Answer 1

1
\$\begingroup\$

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>

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.