Simulate server-side load more

This commit is contained in:
2026-06-04 18:44:58 +02:00
parent b15e7525ce
commit 2a21a4550c
+75 -9
View File
@@ -207,14 +207,14 @@
<div class="sg-large-table__cell" role="cell">E10</div> <div class="sg-large-table__cell" role="cell">E10</div>
</div> </div>
<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row"> <div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row" role="row" data-component-part="large-table-row" data-large-table-load-more-row="true">
<div class="sg-large-table__cell sg-large-table__cell--load-more" role="cell"> <div class="sg-large-table__cell sg-large-table__cell--load-more" role="cell">
<div class="sg-navigation-card-layout sg-large-table__load-more-layout"> <div class="sg-navigation-card-layout sg-large-table__load-more-layout">
<div class="sg-navigation-card-block"> <div class="sg-navigation-card-block">
<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigations-Card"> <article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigations-Card">
<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment"> <div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">
<div class="sg-navigation-card-center"> <div class="sg-navigation-card-center">
<a class="sg-hyperlink" href="#" data-component="hyperlink">Mehr laden</a> <a class="sg-hyperlink" href="#" data-component="hyperlink" data-large-table-load-more-trigger="true">Mehr laden</a>
</div> </div>
</div> </div>
</article> </article>
@@ -235,19 +235,46 @@
const headerCells = Array.from(table.querySelectorAll('[role="columnheader"][data-sort-key]')); const headerCells = Array.from(table.querySelectorAll('[role="columnheader"][data-sort-key]'));
const headerButtons = headerCells.map((cell) => cell.querySelector('.sg-large-table__sort-button')); const headerButtons = headerCells.map((cell) => cell.querySelector('.sg-large-table__sort-button'));
const rows = Array.from(table.querySelectorAll('[data-component-part="large-table-row"]')); const dataRows = Array.from(table.querySelectorAll('[data-component-part="large-table-row"]')).filter((row) => !row.hasAttribute('data-large-table-load-more-row'));
const loadMoreRow = table.querySelector('[data-large-table-load-more-row="true"]');
const loadMoreTrigger = table.querySelector('[data-large-table-load-more-trigger="true"]');
const headerRow = table.querySelector('[data-component-part="large-table-header-row"]'); const headerRow = table.querySelector('[data-component-part="large-table-header-row"]');
const searchInput = table.querySelector('[data-large-table-search]'); const searchInput = table.querySelector('[data-large-table-search]');
const searchFieldWrap = table.querySelector('[data-component="single-line-input"]'); const searchFieldWrap = table.querySelector('[data-component="single-line-input"]');
const searchClearButton = table.querySelector('.sg-input-clear-button'); const searchClearButton = table.querySelector('.sg-input-clear-button');
let searchTimer = null; let searchTimer = null;
let loadMoreTimer = null;
const totalRows = Array.from({ length: 20 }, (_, index) => {
const number = index + 1;
return ['A' + number, 'B' + number, 'C' + number, 'D' + number, 'E' + number];
});
const state = { const state = {
columnIndex: 0, columnIndex: 0,
direction: 'ascending', direction: 'ascending',
query: '', query: '',
loading: false, loadingSearch: false,
loadingMore: false,
loadedCount: dataRows.length,
}; };
function createDataRow(values) {
const row = document.createElement('div');
row.className = 'sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row';
row.setAttribute('role', 'row');
row.setAttribute('data-component-part', 'large-table-row');
row.setAttribute('data-large-table-data-row', 'true');
values.forEach((value) => {
const cell = document.createElement('div');
cell.className = 'sg-large-table__cell';
cell.setAttribute('role', 'cell');
cell.textContent = value;
row.appendChild(cell);
});
return row;
}
function setHeaderState(activeIndex, direction) { function setHeaderState(activeIndex, direction) {
headerCells.forEach((cell, index) => { headerCells.forEach((cell, index) => {
const icon = cell.querySelector('.sg-large-table__sort-icon'); const icon = cell.querySelector('.sg-large-table__sort-icon');
@@ -297,8 +324,8 @@
} }
function renderRows() { function renderRows() {
table.setAttribute('aria-busy', state.loading ? 'true' : 'false'); table.setAttribute('aria-busy', state.loadingSearch || state.loadingMore ? 'true' : 'false');
const sortedRows = rows.slice().sort((leftRow, rightRow) => { const sortedRows = dataRows.slice().sort((leftRow, rightRow) => {
const leftCell = leftRow.querySelectorAll('[role="cell"]')[state.columnIndex]; const leftCell = leftRow.querySelectorAll('[role="cell"]')[state.columnIndex];
const rightCell = rightRow.querySelectorAll('[role="cell"]')[state.columnIndex]; const rightCell = rightRow.querySelectorAll('[role="cell"]')[state.columnIndex];
const leftValue = leftCell ? leftCell.textContent : ''; const leftValue = leftCell ? leftCell.textContent : '';
@@ -314,6 +341,13 @@
row.setAttribute('aria-hidden', isVisible ? 'false' : 'true'); row.setAttribute('aria-hidden', isVisible ? 'false' : 'true');
}); });
if (loadMoreRow) {
const hasMoreRows = state.loadedCount < totalRows.length;
loadMoreRow.classList.toggle('sg-large-table__row--hidden', !hasMoreRows);
loadMoreRow.setAttribute('aria-hidden', hasMoreRows ? 'false' : 'true');
table.appendChild(loadMoreRow);
}
setHeaderState(state.columnIndex, state.direction); setHeaderState(state.columnIndex, state.direction);
} }
@@ -338,7 +372,7 @@
if (searchFieldWrap) { if (searchFieldWrap) {
searchFieldWrap.setAttribute('data-has-value', searchInput.value ? 'true' : 'false'); searchFieldWrap.setAttribute('data-has-value', searchInput.value ? 'true' : 'false');
} }
state.loading = true; state.loadingSearch = true;
renderRows(); renderRows();
if (searchTimer) { if (searchTimer) {
@@ -347,7 +381,7 @@
searchTimer = window.setTimeout(() => { searchTimer = window.setTimeout(() => {
state.query = searchInput.value.trim().toLowerCase(); state.query = searchInput.value.trim().toLowerCase();
state.loading = false; state.loadingSearch = false;
renderRows(); renderRows();
}, 250); }, 250);
}); });
@@ -361,7 +395,7 @@
} }
searchInput.value = ''; searchInput.value = '';
state.query = ''; state.query = '';
state.loading = false; state.loadingSearch = false;
if (searchFieldWrap) { if (searchFieldWrap) {
searchFieldWrap.setAttribute('data-has-value', 'false'); searchFieldWrap.setAttribute('data-has-value', 'false');
} }
@@ -370,6 +404,38 @@
}); });
} }
if (loadMoreTrigger) {
loadMoreTrigger.addEventListener('click', (event) => {
event.preventDefault();
if (state.loadingMore || state.loadedCount >= totalRows.length) {
return;
}
if (loadMoreTimer) {
window.clearTimeout(loadMoreTimer);
}
state.loadingMore = true;
loadMoreTrigger.textContent = 'Lädt ...';
renderRows();
loadMoreTimer = window.setTimeout(() => {
const nextCount = Math.min(state.loadedCount + 5, totalRows.length);
const nextRows = totalRows.slice(state.loadedCount, nextCount).map((values) => createDataRow(values));
nextRows.forEach((row) => {
dataRows.push(row);
});
state.loadedCount = nextCount;
state.loadingMore = false;
loadMoreTrigger.textContent = 'Mehr laden';
renderRows();
}, 350);
});
}
if (headerRow) { if (headerRow) {
setHeaderState(state.columnIndex, state.direction); setHeaderState(state.columnIndex, state.direction);
} }