Here you will learn to build custom data table with:
- Fixed header
- Re-sizable columns
- Horizontal scroll
- Double-click anywhere on table to resize to initial widths
HTML
<template>
<div id="containerDiv" onmousemove={handlemousemove} onmouseup={handlemouseup}
ondblclick={handledblclickresizable}
class="slds-table_header-fixed_container slds-border_right slds-border_left tableScroll"
onscroll={tableOuterDivScrolled}>
<div id="tableViewInnerDiv" onscroll={tableScrolled} class="slds-scrollable_y tableViewInnerDiv">
<table
class="slds-table slds-table_bordered slds-table_header-fixed slds-table_resizable-cols slds-table_fixed-layout">
<thead>
<tr>
<th class="slds-is-resizable dv-dynamic-width" scope="col" style={fixedWidth} title="Column 1">
<div class="slds-cell-fixed" style={fixedWidth}>
<a class="slds-th__action slds-text-link--reset ">
<span class="slds-truncate">Column 1</span>
</a>
<div class="slds-resizable">
<span class="slds-resizable__handle" onmousedown={handlemousedown}>
<span class="slds-resizable__divider"></span>
</span>
</div>
</div>
</th>
<th class="slds-is-resizable dv-dynamic-width" scope="col" style={fixedWidth} title="Column 2">
<div class="slds-cell-fixed" style={fixedWidth}>
<a class="slds-th__action slds-text-link--reset ">
<span class="slds-truncate">Column 2</span>
</a>
<div class="slds-resizable">
<span class="slds-resizable__handle" onmousedown={handlemousedown}>
<span class="slds-resizable__divider"></span>
</span>
</div>
</div>
</th>
<th class="slds-is-resizable dv-dynamic-width" scope="col" style={fixedWidth} title="Column 3">
<div class="slds-cell-fixed" style={fixedWidth}>
<a class="slds-th__action slds-text-link--reset ">
<span class="slds-truncate">Column 3</span>
</a>
<div class="slds-resizable">
<span class="slds-resizable__handle" onmousedown={handlemousedown}>
<span class="slds-resizable__divider"></span>
</span>
</div>
</div>
</th>
<th scope="col">
<div class="slds-cell-fixed">
</div>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Made neat an on be gave show
snug tore neat an on be gave
</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Piqued favour</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>behaviour</div>
</td>
<td></td>
</tr>
<tr>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Made neat an on be gave show
snug tore neat an on be gave
</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Piqued favour</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>behaviour</div>
</td>
<td></td>
</tr>
<tr>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Made neat an on be gave show
snug tore neat an on be gave
</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Piqued favour</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>behaviour</div>
</td>
<td></td>
</tr>
<tr>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Made neat an on be gave show
snug tore neat an on be gave
</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Piqued favour</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>behaviour</div>
</td>
<td></td>
</tr>
<tr>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Made neat an on be gave show
snug tore neat an on be gave
</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Piqued favour</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>behaviour</div>
</td>
<td></td>
</tr>
<tr>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Made neat an on be gave show
snug tore neat an on be gave
</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Piqued favour</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>behaviour</div>
</td>
<td></td>
</tr>
<tr>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Made neat an on be gave show
snug tore neat an on be gave
</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Piqued favour</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>behaviour</div>
</td>
<td></td>
</tr>
<tr>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Made neat an on be gave show
snug tore neat an on be gave
</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Piqued favour</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>behaviour</div>
</td>
<td></td>
</tr>
<tr>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Made neat an on be gave show
snug tore neat an on be gave
</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Piqued favour</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>behaviour</div>
</td>
<td></td>
</tr>
<tr>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Made neat an on be gave show
snug tore neat an on be gave
</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>Piqued favour</div>
</td>
<td>
<div class="slds-truncate dv-dynamic-width" style={fixedWidth}>behaviour</div>
</td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
JS
import {
LightningElement, track
} from 'lwc';
export default class DemoDataViewFieldsConfig extends LightningElement {
fixedWidth = "width:15rem;";
//FOR HANDLING THE HORIZONTAL SCROLL OF TABLE MANUALLY
tableOuterDivScrolled(event) {
this._tableViewInnerDiv = this.template.querySelector(".tableViewInnerDiv");
if (this._tableViewInnerDiv) {
if (!this._tableViewInnerDivOffsetWidth || this._tableViewInnerDivOffsetWidth === 0) {
this._tableViewInnerDivOffsetWidth = this._tableViewInnerDiv.offsetWidth;
}
this._tableViewInnerDiv.style = 'width:' + (event.currentTarget.scrollLeft + this._tableViewInnerDivOffsetWidth) + "px;" + this.tableBodyStyle;
}
this.tableScrolled(event);
}
tableScrolled(event) {
if (this.enableInfiniteScrolling) {
if ((event.target.scrollTop + event.target.offsetHeight) >= event.target.scrollHeight) {
this.dispatchEvent(new CustomEvent('showmorerecords', {
bubbles: true
}));
}
}
if (this.enableBatchLoading) {
if ((event.target.scrollTop + event.target.offsetHeight) >= event.target.scrollHeight) {
this.dispatchEvent(new CustomEvent('shownextbatch', {
bubbles: true
}));
}
}
}
//#region ***************** RESIZABLE COLUMNS *************************************/
handlemouseup(e) {
this._tableThColumn = undefined;
this._tableThInnerDiv = undefined;
this._pageX = undefined;
this._tableThWidth = undefined;
}
handlemousedown(e) {
if (!this._initWidths) {
this._initWidths = [];
let tableThs = this.template.querySelectorAll("table thead .dv-dynamic-width");
tableThs.forEach(th => {
this._initWidths.push(th.style.width);
});
}
this._tableThColumn = e.target.parentElement;
this._tableThInnerDiv = e.target.parentElement;
while (this._tableThColumn.tagName !== "TH") {
this._tableThColumn = this._tableThColumn.parentNode;
}
while (!this._tableThInnerDiv.className.includes("slds-cell-fixed")) {
this._tableThInnerDiv = this._tableThInnerDiv.parentNode;
}
console.log("handlemousedown this._tableThColumn.tagName => ", this._tableThColumn.tagName);
this._pageX = e.pageX;
this._padding = this.paddingDiff(this._tableThColumn);
this._tableThWidth = this._tableThColumn.offsetWidth - this._padding;
console.log("handlemousedown this._tableThColumn.tagName => ", this._tableThColumn.tagName);
}
handlemousemove(e) {
console.log("mousemove this._tableThColumn => ", this._tableThColumn);
if (this._tableThColumn && this._tableThColumn.tagName === "TH") {
this._diffX = e.pageX - this._pageX;
this.template.querySelector("table").style.width = (this.template.querySelector("table") - (this._diffX)) + 'px';
this._tableThColumn.style.width = (this._tableThWidth + this._diffX) + 'px';
this._tableThInnerDiv.style.width = this._tableThColumn.style.width;
let tableThs = this.template.querySelectorAll("table thead .dv-dynamic-width");
let tableBodyRows = this.template.querySelectorAll("table tbody tr");
let tableBodyTds = this.template.querySelectorAll("table tbody .dv-dynamic-width");
tableBodyRows.forEach(row => {
let rowTds = row.querySelectorAll(".dv-dynamic-width");
rowTds.forEach((td, ind) => {
rowTds[ind].style.width = tableThs[ind].style.width;
});
});
}
}
handledblclickresizable() {
let tableThs = this.template.querySelectorAll("table thead .dv-dynamic-width");
let tableBodyRows = this.template.querySelectorAll("table tbody tr");
tableThs.forEach((th, ind) => {
th.style.width = this._initWidths[ind];
th.querySelector(".slds-cell-fixed").style.width = this._initWidths[ind];
});
tableBodyRows.forEach(row => {
let rowTds = row.querySelectorAll(".dv-dynamic-width");
rowTds.forEach((td, ind) => {
rowTds[ind].style.width = this._initWidths[ind];
});
});
}
paddingDiff(col) {
if (this.getStyleVal(col, 'box-sizing') === 'border-box') {
return 0;
}
this._padLeft = this.getStyleVal(col, 'padding-left');
this._padRight = this.getStyleVal(col, 'padding-right');
return (parseInt(this._padLeft, 10) + parseInt(this._padRight, 10));
}
getStyleVal(elm, css) {
return (window.getComputedStyle(elm, null).getPropertyValue(css))
}
}
CSS
.tableScroll {
overflow: auto;
overflow-y: hidden;
height: 10rem;
}
did it in a single line of code.
LikeLike