CASE: how to use grouping for HTML tables

We might want to use a table that overviews several categories, where each category has its own details. When exporting such a table, you want the details of each category to be grouped together. Meaning that they don’t get printed onto several pages.

In Markdown, this was possible by making sure the grouped tables are re-created inside group-tags (basically, a new table was created every time grouping was needed):

{% comment %}below Markdown table gets grouped on the use of group-tags{% endcomment %}
{% stripnewlines %}
| Header 1
| Header 2
{% newline %}
|--------
|--------+
{% newline %}
| content
| content
{% endstripnewlines %}

{% nic %}
{::group}
{:/group}
{% endnic %}

{% comment %}re-create the to be grouped table{% endcomment %}
{% stripnewlines %}
{% newline %}
|--------
|--------+
{% newline %}
| content
| content
{% endstripnewlines %}

In HTML-tables, we do support repeated headers (class usr-repeated-header), which means the repeated header functionality should not get broken as soon as we replicate the tables for each grouping (as the functionality of the repeated header would get reset for each new table).

However, a new class was introduced in HTML-tables: usr-hide-samepage-header
This class allows us to split the table (just as we did with Markdown tables), ensuring the header is skipped when the new table starts on the same page as the previous table, but is added again (and repeated) when a new page starts.

An example
Let’s say we want to overview a whole range of assets, divided into several categories, where each will display:

  • account number
  • account name
  • current year end value
  • previous year end value

Because it could be a large table, repeated headers would be ideal to make sure the header is repeated on each new page, to be more clear when the table is exported to PDF on several pages.

We’ll build this into a reconciliation, and create the following parts first:

part variables

{% comment %}create array with fixed ranges and key (to create translation){% endcomment %}
{% assign assets_array = "211;fa_1|212;fa_2|213;fa_3|214;fa_4|221;fa_5|222;fa_6|223;fa_7|224;fa_8" | split:"|" %}

{% comment %}period vars needed for column headers{% endcomment %}
{% assign date_cy = period.end_date | date:"%d/%m/%Y" %}
{% assign date_py = period.minus_1y.end_date | date:"%d/%m/%Y" %}

{% comment %}special var to be used to activate class "usr-hide-samepage-header"{% endcomment %}
{% assign skip_header = false %}

{% comment %}force export to landscape{% endcomment %}
{% changeorientation "landscape" %}

We’ll discuss some of these variables when we create the needed tables.

part translations

{% t= "fa_1" default:"Cost of development" %}
{% t= "fa_2" default:"Concessions, patents, licences, trademarks and similar rights and assets" %}
{% t= "fa_3" default:"Goodwill, to the extent that it was acquired for valuable consideration" %}
{% t= "fa_4" default:"Payments on account and intangible assets under development" %}
{% t= "fa_5" default:"Land and buildings" %}
{% t= "fa_6" default:"Plant and machinery" %}
{% t= "fa_7" default:"Other fixtures and fittings, tools and equipment" %}
{% t= "fa_8" default:"Payments on account and tangible assets in the course of construction" %}
{% t= "acc_name" default:"Account name" %}
{% t= "acc_nbr" default:"Account number" %}

part table_head_definition

<thead class="usr-repeated-header {% if skip_header %}usr-hide-samepage-header{% endif %}">
  <tr>
    <th class="usr-width-35">&nbsp;</th>
    <th class="usr-line-bottom usr-width-10">**{% t "acc_nbr" %}**</th>
    <th class="usr-line-bottom usr-width-25">**{% t "acc_name" %}**</th>
    <th class="usr-align-right usr-line-bottom usr-width-15">**{{ date_cy }}**</th>
    <th class="usr-align-right usr-line-bottom usr-width-15">**{{ date_py }}**</th>
  </tr>
</thead> 

This part will be executed multiple times: in the very first table and later on for each grouped (new) table.
The variable skip_header will be false in the very first table, but will be set on true after, so the class usr-hide-samepage-header can be used.

main

{% comment %}access local variables{% endcomment %}
{% include "parts/variables" %}
{% comment %}access translations{% endcomment %}
{% include "parts/translations" %}

{% comment %}
====================
    TABLE HEADER
====================
{% endcomment %}
<table class="usr-width-100">
  
  {% comment %}table head will be used more than once, while the first time class "usr-hide-samepage-header" is not needed the first time{% endcomment %}
  {% include "parts/table_head_definition" %}
  
  {% comment %}empty body needed{% endcomment %}
  <tbody>

  </tbody>
</table>

{% comment %}
=====================
    TABLE DETAILS
=====================
{% endcomment %}
{% comment %}set special var on "true" so class "usr-hide-samepage-header" will be activated in part "table_head_definition"{% endcomment %}
{% assign skip_header = true %}

{% comment %}create table for each category as it needs grouping{% endcomment %}
{% for cat in assets_array %}

  {% comment %}create needed vars{% endcomment %}
  {% assign cat_elements = cat | split:";" %}
    {% assign cat_range = cat_elements[0] %}
    {% assign cat_title = cat_elements[1] %}
    
  {% comment %}create translation{% endcomment %}
  {% capture cat_name %}{% t cat_title %}{% endcapture %}
    
  {% comment %}create accounts drop{% endcomment %}
  {% assign cat_accounts = period.accounts | range:cat_range %}

  {% comment %}re-create table head for each category{% endcomment %}
  <table class="usr-width-100">
    
    {% comment %}make sure table definition is created but hidden from output if on same page{% endcomment %}
    {% include "parts/table_head_definition" %}   
    
    {% comment %}create categories with their details{% endcomment %}
    <tbody>
      
      {% comment %}row with just the category name{% endcomment %}
      <tr>
        <td class="">{::font size='l'}{{ cat_name }}{:/font}</td>
        <td class="">&nbsp;</td>
        <td class="">&nbsp;</td>
        <td class="">&nbsp;</td>
        <td class="">&nbsp;</td>
      </tr>
      
      {% comment %}for each category, show the related accounts and their info{% endcomment %}
      {% for acc in cat_accounts %}
      
        {% comment %}create account end value for current and last year{% endcomment %}
        {% assign acc_mapped_nbr = acc.mapped_number %}
          {% assign acc_value_cy = period.accounts | range:acc_mapped_nbr %}
          {% assign acc_value_py = period.minus_1y.accounts | range:acc_mapped_nbr %}
      
        <tr>
          {% comment %}empty cell{% endcomment %}
          <td class="">&nbsp;</td>
          {% comment %}Account number{% endcomment %}
          <td class="">{% linkto acc %}{{ acc.mapped_number }}{% endlinkto %}</td>
          {% comment %}Account name{% endcomment %}
          <td class="">{{ acc.name }}</td>
          {% comment %}Account value current period{% endcomment %}
          <td class="usr-align-right">{{ acc_value_cy | currency }}</td>
          {% comment %}Account value last year{% endcomment %}
          <td class="usr-align-right">{{ acc_value_py | currency }}</td>
        </tr>      
      
      {% endfor %}
      
      
    </tbody>
  </table>

{% comment %}make sure tables get grouped{% endcomment %}
{% nic %}
{:/group}
{::group}
{% endnic %}

{% endfor %} 

So, we first create a table and access the thead section, which is coded in a separate part called table_head_definition; keep in mind the new class usr-hide-samepage-header is not executed here yet:

{% comment %}
====================
    TABLE HEADER
====================
{% endcomment %}
<table class="usr-width-100">
  
  {% comment %}table head will be used more than once, while the first time class "usr-hide-samepage-header" is not needed the first time{% endcomment %}
  {% include "parts/table_head_definition" %}
  
  {% comment %}empty body needed{% endcomment %}
  <tbody>

  </tbody>
</table> 

We now have created the headers of our table, which now needs to be repeated on every new page. More so, this same header definition needs to be executed for every new table we want to group (for each category), while making sure the header is not shown twice on the same page (if 2 categories are printed on a single page).

This is why we now set the variable on true:

{% assign skip_header = true %} 

We will now loop over our array (as everything will be originated from that), and create a table for each category. But now the part table_head_definition will execute the new class usr-hide-samepage-header:

{% for cat in assets_array %}

  ... 

  {% comment %}re-create table head for each category{% endcomment %}
  <table class="usr-width-100">
    
    {% comment %}make sure table definition is created but hidden from output if on same page{% endcomment %}
    {% include "parts/table_head_definition" %}   
    
    {% comment %}create categories with their details{% endcomment %}
    <tbody>
      
      {% comment %}row with just the category name{% endcomment %}
      <tr>
        ...
      </tr>
      
      {% comment %}for each category, show the related accounts and their info{% endcomment %}
      {% for acc in cat_accounts %}
      
        ...
      
        <tr>
          ...
        </tr>      
      
      {% endfor %}
      
      
    </tbody>
  </table>

{% comment %}make sure tables get grouped{% endcomment %}
{% nic %}
{:/group}
{::group}
{% endnic %}    

{% endfor %} 

At the end of the table, we make sure the table gets grouped:

{% comment %}make sure tables get grouped{% endcomment %}
{% nic %}
{:/group}
{::group}
{% endnic %}

The result is something like this, where all categories are nicely grouped, and if they appear on a new page, the header is repeated as well
HTML_grouping_case.pdf (44.1 KB)