Home > Mobile >  how to make colspan of table footer flexible with javascript/jQuery?
how to make colspan of table footer flexible with javascript/jQuery?

Time:05-12

I've a dynamic html table where I want to place sums in the footer at certein calculated positions. Those fields have a fixed colspan of 1. Other fields should be displayed as single column with variable colspan.

In my example below, I want to add those footer sums at positions, where the header contains the word "Sum" - note that those sums could occour on any position in the table.

All the header data and the "needle" fields are stored in arrays.

I'm getting the positions of the needles in the header array with position = header.indexOf(column); //position of current needle

Afterwards the colspan is calculated with colSpan = position - last_pos - el_span; //calculate colspan

Finally, the elements are added to the footer using

$('#testTable tfoot tr').append("<th colspan=" colSpan "></th>");
$('#testTable tfoot tr').append("<th colspan=" el_span ">Sum</th>");

Somehow, the first sum field is always on the wrong position - how to adapt my algorithm to fix that issue?

enter image description here

$(document).ready(function(){
  const header    = ["Info","Info","Info","Info","Sum1","Sum2","Info","Sum3","Info","Info","Sum4"];
  const needles   = ["Sum1","Sum2","Sum3","Sum4"];
  const el_span   = 1; //fixed colspan for sum column
  let   position  = 0; //position pointer, starting from 0
  let   last_pos  = 0; //last position stored
  let   colSpan   = 0; //calculated colspan, starting with 0
  
  for(const column of needles)
  {
    position = header.indexOf(column); //position of current needle
    colSpan  = position - last_pos - el_span; //calculate colspan
    last_pos = position;
    
    $('#testTable tfoot tr').append("<th colspan=" colSpan "></th>");
    $('#testTable tfoot tr').append("<th colspan=" el_span ">Sum</th>");
  }
  
});
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="testTable" >
  <thead>
    <tr>
      <th>Info</th>
      <th>Info</th>
      <th>Info</th>
      <th>Info</th>
      <th>Sum</th>
      <th>Sum</th>
      <th>Info</th>
      <th>Sum</th>
      <th>Info</th>
      <th>Info</th>
      <th>Sum</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>23</td>
      <td>2</td>
      <td>Text</td>
      <td>245</td>
      <td>Text</td>
      <td>Text</td>
      <td>4</td>
    </tr>
    <tr>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>23</td>
      <td>2</td>
      <td>Text</td>
      <td>245</td>
      <td>Text</td>
      <td>Text</td>
      <td>4</td>
    </tr>
    <tr>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>23</td>
      <td>2</td>
      <td>Text</td>
      <td>245</td>
      <td>Text</td>
      <td>Text</td>
      <td>4</td>
    </tr>
    <tr>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>23</td>
      <td>2</td>
      <td>Text</td>
      <td>245</td>
      <td>Text</td>
      <td>Text</td>
      <td>4</td>
    </tr>    
  </tbody>
  <tfoot>
    <tr>
    
    </tr>
  </tfoot>
</table>

CodePudding user response:

A Table Builder

This solution has a tableBuilder function that creates the table from the header array and accepts optional parameters for caption and row count. Since the header columns determine the footer layout the "needles" property seems extraneous and is not used. There's no need to use jQuery, especially since the dependency has been removed from Bootstrap 5.

The snippet creates 2 tables, one from the header array and another from the reversed header array. The sum columns may be moved around in any order and the colspans are calculated correctly. And if OP only wants the footer, and not the entire table, it would be easy to modify the builder to add only that part.

Run the code snippet to try.

You may need to scroll down to view the second table

const header = ["Info", "Info", "Info", "Info", "Sum1", "Sum2", "Info", "Sum3", "Info", "Info", "Sum4"];

function tableBuilder(selector, header, caption, rowCount) {

  let thead = "",
    tbody = "",
    tfoot = "",
    row = "",
    n = 0;

  header.forEach(p => {

    thead  = `<th>${p}</th>`;

    row  = `<td> </td>`;

    if (p.indexOf("Sum") >= 0) {
      if (n > 0) tfoot  = `<th colspan="${n}"></td>`;
      tfoot  = `<th>${p}</th>`;
      n = 0;
    } else n  ;

  });
  
  // add last column when not a sum
  if (n > 0) tfoot  = `<th colspan="${n}"></th>`;
  
  for (n = 0; n < (rowCount || 4); n  ) tbody  = `<tr>${row}</tr>`;

  let table = document.querySelector(selector);

  table.innerHTML = `
  <caption>${caption || "Table"}</caption>
  <thead ><tr>${thead}</tr></thead>
  <tbody>${tbody}</tbody>
  <tfoot ><tr>${tfoot}</tr></tfoot>
  `;

}

// Test

tableBuilder("#table1", header, "Table", 2);

tableBuilder("#table2", header.reverse(), "Table - Reversed Header", 4);
th {
  font-size: 0.6rem;
}

.table caption {
  font-weight: bold;
}
<div >
  <table id="table1" ></table>
  <table id="table2" ></table>
</div>

<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">

CodePudding user response:

I managed it by creating a new spans[] array (initially containing an object {text:'', colspan:0}) and a cursor, updated on certain conditions while looping inside the header[] array.

Then I loop the header[].

Each time a header[] element is not inside the needles[] array, I increment the colspan value of the object inside span[].

If the header element is included in the needles[] array, I add a new object to the spans[] array.

At the end, I have an array with texts and colspans for each footer element to append.

It seems to work well, it also doesn't care of the order of elements inside the needles[] array.

Run the snippet Full-Page, to avoid the console.log() overlapping the table).

$(document).ready(function() {
  const header = ["Info", "Info", "Info", "Info", "Sum1", "Sum2", "Info", "Sum3", "Info", "Info", "Sum4"];
  const needles = ["Sum1", "Sum2", "Sum3", "Sum4"];

  const spans = []; // new array
  let cursor = 0; // cursor
  spans[cursor] = {
    text: '',
    colspan: 0
  };

  for (let i = 0; i < header.length; i  ) {
    if (!needles.includes(header[i])) { // if not included,   colspan
      spans[cursor].colspan  ;
    } else {
      if (i !== 0) cursor  ; // only needed when we have a needle
                             // in the first header element

      // here I create the new objects
      // with the text Sum1, Sum2, etc
      // and colspan=1
      spans[cursor] = {};
      spans[cursor].text = header[i];
      spans[cursor].colspan = 1;

      if (i === header.length - 1) continue; // if I am at the end 
                                             // of the header array,
                                             // skip the next block


      // if the next element in the header array is not included
      // in needles, I already create a new element with
      // colspan = 0 for the next loop.
      // If the next element is also in needles it's not necessary
      // as it will be catched by else{} block in the next loop
      if (!needles.includes(header[i   1])) {
        cursor  ;
        spans[cursor] = {};
        spans[cursor].text = '';
        spans[cursor].colspan = 0;
      }
    }
  }

  console.log(spans);

  for (const span of spans) {
    $('#testTable tfoot tr').append(`<th colspan="${span.colspan}">${span.text}</th>`);
  }
});
.as-console-wrapper {
  max-height: 150px !important;
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="testTable" >
  <thead>
    <tr>
      <th>Info</th>
      <th>Info</th>
      <th>Info</th>
      <th>Info</th>
      <th>Sum</th>
      <th>Sum</th>
      <th>Info</th>
      <th>Sum</th>
      <th>Info</th>
      <th>Info</th>
      <th>Sum</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>23</td>
      <td>2</td>
      <td>Text</td>
      <td>245</td>
      <td>Text</td>
      <td>Text</td>
      <td>4</td>
    </tr>
    <tr>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>23</td>
      <td>2</td>
      <td>Text</td>
      <td>245</td>
      <td>Text</td>
      <td>Text</td>
      <td>4</td>
    </tr>
    <tr>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>23</td>
      <td>2</td>
      <td>Text</td>
      <td>245</td>
      <td>Text</td>
      <td>Text</td>
      <td>4</td>
    </tr>
    <tr>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>Text</td>
      <td>23</td>
      <td>2</td>
      <td>Text</td>
      <td>245</td>
      <td>Text</td>
      <td>Text</td>
      <td>4</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>

    </tr>
  </tfoot>
</table>

  • Related