Custom table elements not splitting correctly
Currently if i am using a custom element using lit-element
, and the table size is greater than the remaining size on the page, the table will cut off the rows that contain the data that does not fit within the bounds instead of splitting. My document contains several of these custom tables, so the workaround that I've used is to recalculate the each table based on the remaining page height, split any overflow into a brand new table element, and then recalculate all subsequent tables.
<caption>
${this.tableNum ? `Table ${this.tableNum} - ` : ''}
<slot></slot>
${this.isContinued ? `, continued` : ''}
</caption>
<thead>
<tr>
${this.getHeaders().order.map(header => {
return html`
<th>${this.getPrettyPrintMap()[header]}</th>
`;
})}
</tr>
</thead>
<tbody>
${this.getRowData().map(row => {
return html`
${this.getRow(row, this.getHeaders().order)}
`;
})}
</tbody>
</table>
This is the code for the table, the rows and headers are dynamic based on the ingested data.
Here is how I've been calculating the table overflow which runs on the browser. Note that because there is an infinite loop if the table overflow is too great, the dimensions of the page have been calculated before this.
function splitTableData(table, pageHeight, offset = 0) {
// we need to do our calculations on the actual HTML, not the component
let splitdata = [];
let tableroot = table.shadowRoot.firstElementChild;
let tableData = JSON.parse(table.getAttribute('data'));
let caption = tableroot.querySelector('caption');
let headers = tableroot.querySelector('thead');
let tbody = tableroot.querySelector('tbody');
let padding = tableroot.offsetHeight - caption.offsetHeight - headers.offsetHeight - tbody.offsetHeight;
let rows = tbody.children;
// offsetTop will give us the padding from table to headers
let splitTableHeight = headers.offsetHeight + headers.offsetTop + padding + offset;
let currentIndex = 0;
let startIndex = currentIndex;
while (currentIndex < rows.length) {
// if we don't have space for this row, push what we have as one table element and continue
if (splitTableHeight + rows[currentIndex].offsetHeight > pageHeight) {
splitdata.push({
...tableData,
data: tableData.data.slice(startIndex, currentIndex)
});
splitTableHeight = headers.offsetHeight + headers.offsetTop + padding;
startIndex = currentIndex;
} else {
// If we reached the end of the iteration, need to make sure that we add this portion to our slice
// specifically if slice.height < pageHeight
if (currentIndex === rows.length - 1) {
splitdata.push({
...tableData,
data: tableData.data.slice(startIndex, currentIndex + 1)
});
} else {
// grow our table slice
splitTableHeight += rows[currentIndex].offsetHeight;
}
currentIndex++;
}
}
return splitdata;
}
After I've calculated how many tables we need to split the table into, i create a new table for each object in the list and place them on the page. i then loop through all the other tables and do the same. I'll omit the code i use for that portion but can attach if necessary.
The flow for this workaround is as follows: run headless browser -> run pagedjs -> calculate table dimensions -> split into separate tables -> run new page with the set tables -> repeat on subsequent tables
Ideally I would just want to use pagedjs to do this, but this workaround has helped me for this problem.