I managed to implement a kind of infinite scroll on a table. Basically I only fetch the rows I need to display along with some extra cache ones. When I scroll I add some extra rows again to fill the gap.
I still need some adjustments but it works well. The problem now is that I need to implement the logic in several pages which requires lots of boiler plate.
I wonder if it this possible to encapsulate all the stuf in a webcomponent virtual-table
. Is there a way to inject the content of the table from the controller?
var Content = class Content {
// Models the table header, rows as well as methods to prepend or appends rows (when scrolling).
}
I try to use the controller name from the attribute and fetch
the content, but the main issue I see comes from the promise
which I don't seem the be able to pass to the content member of the class because of the asynchronicity. I initialy used an async / await
method but I don't think it makes sense with webcomponent.
export default class VirtualTable extends HTMLElement {
static get observedAttributes() {
return ['controller'];
}
content = null;
constructor() {
super();
this.content = this.getContent(0); // Returns null!
}
getContent(index) {
var body = JSON.stringify({
Index: index
});
// Gets the content from the controller.
const fetchPromise = fetch(`${window.location.href}${this.controller}/GetContent/`, {
method: 'POST',
body: body,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8'
}
});
fetchPromise.then((response) => {
var jsonPromise = response.json();
jsonPromise.then((json) => {
return new Content(json); // Correctly instantiate the Content class.
});
});
}
}
<body>
<virtual-table controller="items">
</virtual-table>
</body>
<script type="module">
import VirtualTable from './scripts/VirtualTable.js'
customElements.define('virtual-table', VirtualTable);
</script>
Does anyone have some insights?
async/await
makes for compacter code
Imported part is to not do DOM updates in the constructor
phase;
only once the connectedCallback
runs do you know the Elements are IN the DOM or can be added to the DOM
Since the constructor
may not be async
(needed for await), you can 't do the fetch there; you can resort to a promissed fetch.
The scroll part is up to you..
customElements.define("json-table", class extends HTMLElement {
constructor(){
super().attachShadow({mode:"open"}).innerHTML =
`<table><thead>`+
`<tr><th>id</th><th>firstName</th><th>lastName</th></tr>`+
`<thead>` +
`<tbody></tbody>` +
`</table>`;
this.tbody = this.shadowRoot.querySelector("tbody");
}
async connectedCallback() {
let json = await (await fetch(this.getAttribute("endpoint"))).json();
json.users.forEach(user => this.add(user));
}
add(user){
let tr = document.createElement("tr");
tr.innerHTML = ["id","firstName","lastName"]
.map(key=>`<td>${user[key]}</td>`).join("");
this.tbody.append(tr);
}
})
<json-table endpoint='https://dummyjson.com/users' ></json-table>
And before you ask for <slot>
elements inside <table>
(which can't be done),
do read and understand: https://github.com/WICG/webcomponents/issues/630