@jinntec/fore
Version:
Fore - declarative user interfaces in plain HTML
90 lines (74 loc) • 3.17 kB
JavaScript
export class FxSelect extends HTMLElement {
constructor() {
super();
// Attach Shadow DOM to encapsulate the component
this.attachShadow({ mode: 'open' });
// Create and attach the <select> element
this.selectElement = document.createElement('select');
this.shadowRoot.appendChild(this.selectElement);
// Set default values
this.batchSize = parseInt(this.getAttribute('batch-size')) || 20;
this.size = parseInt(this.getAttribute('size')) || 5;
this.currentLoadedItems = 0;
this.hasMoreItems = true; // Assume there are more items initially
// Set the size of the <select> element
this.selectElement.setAttribute('size', this.size);
// Bind the scroll event handler
this.handleScroll = this.handleScroll.bind(this);
}
connectedCallback() {
// Initial load of options
this.loadOptions(this.currentLoadedItems, this.batchSize);
// Attach scroll event listener
this.selectElement.addEventListener('scroll', this.handleScroll);
}
disconnectedCallback() {
// Clean up event listeners when the element is removed
this.selectElement.removeEventListener('scroll', this.handleScroll);
}
// Mock function to simulate fetching more options
fetchMoreItems(start, count) {
// Simulate an async fetch or data load (replace with real fetch if needed)
return new Promise((resolve) => {
setTimeout(() => {
const items = [];
for (let i = start; i < start + count; i++) {
if (i < 200) { // Let's say we stop after 200 items (remove this limit for real use)
items.push({ value: i, label: `Option ${i + 1}` });
}
}
resolve(items);
}, 500); // Simulate fetch delay
});
}
// Method to load a batch of options
async loadOptions(start, count) {
const fragment = document.createDocumentFragment();
const newItems = await this.fetchMoreItems(start, count);
if (newItems.length > 0) {
newItems.forEach(item => {
const option = document.createElement('option');
option.value = item.value;
option.textContent = item.label;
fragment.appendChild(option);
});
this.selectElement.appendChild(fragment);
this.currentLoadedItems += newItems.length;
} else {
// If no more items are returned, stop further loading
this.hasMoreItems = false;
}
}
// Scroll event handler to load more items
handleScroll() {
const { scrollTop, scrollHeight, clientHeight } = this.selectElement;
const isNearBottom = scrollTop + clientHeight >= scrollHeight - 10;
if (isNearBottom && this.hasMoreItems) {
this.loadOptions(this.currentLoadedItems, this.batchSize);
}
}
}
// Register the custom element
if (!customElements.get('fx-select')) {
customElements.define('fx-select', FxSelect);
}