Skip to content

Commit 8d39a5c

Browse files
authored
fix: reset fetch range when requested page is out of visible range (#7316)
* fix: reset fetch range when requested page is out of visible range
1 parent b9884f7 commit 8d39a5c

1 file changed

Lines changed: 52 additions & 28 deletions

File tree

  • vaadin-grid-flow-parent/vaadin-grid-flow/src/main/resources/META-INF/resources/frontend

vaadin-grid-flow-parent/vaadin-grid-flow/src/main/resources/META-INF/resources/frontend/gridConnector.js

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@
207207
grid.activeItem = item;
208208
}
209209
});
210-
210+
211211
grid.selectedItems = Object.values(selectedKeys);
212212
});
213213

@@ -277,16 +277,23 @@
277277
detailsVisibleOnClick = visibleOnClick;
278278
});
279279

280-
grid.$connector._getPageIfSameLevel = tryCatchWrapper(function(parentKey, index, defaultPage) {
281-
let cacheAndIndex = grid._cache.getCacheAndIndex(index);
282-
let parentItem = cacheAndIndex.cache.parentItem;
283-
let parentKeyOfIndex = (parentItem) ? grid.getItemId(parentItem) : root;
284-
if(parentKey !== parentKeyOfIndex) {
285-
return defaultPage;
286-
} else {
287-
return grid._getPageForIndex(cacheAndIndex.scaledIndex);
280+
grid.$connector._getSameLevelPage = tryCatchWrapper(function (parentKey, currentCache, currentCacheItemIndex) {
281+
const currentParentKey = currentCache.parentItem ? grid.getItemId(currentCache.parentItem) : root;
282+
if (currentParentKey === parentKey) {
283+
// Level match found
284+
return grid._getPageForIndex(currentCacheItemIndex);
288285
}
289-
})
286+
const { parentCache } = currentCache;
287+
if (!parentCache) {
288+
// There is no parent cache to match level
289+
return null;
290+
}
291+
const parentCacheItemIndex = Object.entries(parentCache.itemCaches).find(
292+
([index, cache]) => cache === currentCache
293+
)[0];
294+
// Traverse the tree upwards until a match is found or the end is reached
295+
return this._getSameLevelPage(parentKey, parentCache, parentCacheItemIndex);
296+
});
290297

291298
grid.$connector.getCacheByKey = tryCatchWrapper(function(key) {
292299
let cacheAndIndex = grid._cache.getCacheAndIndexByKey(key);
@@ -350,39 +357,56 @@
350357
})
351358

352359
grid.$connector.fetchPage = tryCatchWrapper(function(fetch, page, parentKey) {
360+
// Adjust the requested page to be within the valid range in case
361+
// the grid size has changed while fetchPage was debounced.
362+
if (parentKey === root) {
363+
page = Math.min(page, Math.floor((grid.size - 1) / grid.pageSize));
364+
}
365+
353366
// Determine what to fetch based on scroll position and not only
354367
// what grid asked for
368+
let start = grid._virtualStart;
369+
let end = grid._virtualEnd;
355370

356371
// The buffer size could be multiplied by some constant defined by the user,
357372
// if he needs to reduce the number of items sent to the Grid to improve performance
358373
// or to increase it to make Grid smoother when scrolling
359-
let start = grid._virtualStart;
360-
let end = grid._virtualEnd;
361374
let buffer = end - start;
362375

363376
let firstNeededIndex = Math.max(0, start + grid._vidxOffset - buffer);
364377
let lastNeededIndex = Math.min(end + grid._vidxOffset + buffer, grid._effectiveSize);
365378

366-
let firstNeededPage = page;
367-
let lastNeededPage = page;
379+
let pageRange = [null, null];
368380
for(let idx = firstNeededIndex; idx <= lastNeededIndex; idx++) {
369-
firstNeededPage = Math.min(firstNeededPage, grid.$connector._getPageIfSameLevel(parentKey, idx, firstNeededPage));
370-
lastNeededPage = Math.max(lastNeededPage, grid.$connector._getPageIfSameLevel(parentKey, idx, lastNeededPage));
381+
const { cache, scaledIndex } = grid._cache.getCacheAndIndex(idx);
382+
383+
const sameLevelPage = grid.$connector._getSameLevelPage(parentKey, cache, scaledIndex);
384+
if (sameLevelPage === null) {
385+
continue;
386+
}
387+
388+
pageRange[0] = Math.min(pageRange[0] !== null ? pageRange[0] : sameLevelPage, sameLevelPage);
389+
pageRange[1] = Math.max(pageRange[1] !== null ? pageRange[1] : sameLevelPage, sameLevelPage);
371390
}
372391

373-
let firstPage = Math.max(0, firstNeededPage);
374-
let lastPage = (parentKey !== root) ? lastNeededPage: Math.min(lastNeededPage, Math.floor(grid.size / grid.pageSize));
375-
let lastRequestedRange = lastRequestedRanges[parentKey];
376-
if(!lastRequestedRange) {
377-
lastRequestedRange = [-1, -1];
392+
// When the viewport doesn't contain the requested page or it doesn't contain any items from
393+
// the requested level at all, it means that the scroll position has changed while fetchPage
394+
// was debounced. For example, it can happen if the user scrolls the grid to the bottom and
395+
// then immediately back to the top. In this case, the request for the last page will be left
396+
// hanging. To avoid this, as a workaround, we reset the range to only include the requested page
397+
// to make sure all hanging requests are resolved. After that, the grid requests the first page
398+
// or whatever in the viewport again.
399+
if (pageRange.some((p) => p === null) || page < pageRange[0] || page > pageRange[1]) {
400+
pageRange = [page, page];
378401
}
379-
if (lastRequestedRange[0] != firstPage || lastRequestedRange[1] != lastPage) {
380-
lastRequestedRange = [firstPage, lastPage];
381-
lastRequestedRanges[parentKey] = lastRequestedRange;
382-
let count = lastPage - firstPage + 1;
383-
fetch(firstPage * grid.pageSize, count * grid.pageSize);
402+
403+
let lastRequestedRange = lastRequestedRanges[parentKey] || [-1, -1];
404+
if (lastRequestedRange[0] != pageRange[0] || lastRequestedRange[1] != pageRange[1]) {
405+
lastRequestedRanges[parentKey] = pageRange;
406+
let pageCount = pageRange[1] - pageRange[0] + 1;
407+
fetch(pageRange[0] * grid.pageSize, pageCount * grid.pageSize);
384408
}
385-
})
409+
});
386410

387411
grid.dataProvider = tryCatchWrapper(function(params, callback) {
388412
if (params.pageSize != grid.pageSize) {
@@ -906,7 +930,7 @@
906930
const callback = rootPageCallbacks[page];
907931
if ((cache[root] && cache[root][page]) || page < lastRequestedRange[0] || +page > lastRequestedRangeEnd) {
908932
delete rootPageCallbacks[page];
909-
933+
910934
if (cache[root][page]) {
911935
// Cached data is available, resolve the callback
912936
callback(cache[root][page]);

0 commit comments

Comments
 (0)