Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions e2e/testcafe-devextreme/tests/dataGrid/common/scrolling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ async function getTestLoadCount(): Promise<number> {
return ClientFunction(() => (window as any).testLoadCount as number)();
}

async function getTestLoadOptions(): Promise<{ skip: number; take: number }[]> {
return ClientFunction(
() => (window as any).testLoadOptions as { skip: number; take: number }[],
)();
}

fixture.disablePageReloads`Scrolling`
.page(url(__dirname, '../../container.html'));

Expand Down Expand Up @@ -2161,6 +2167,74 @@ test('DataGrid - The "row" parameter in the FocusedRowChanged event refers to a
});
});

test('Remote virtual scrolling should send one request on init when starting on a non-first page with async templates (T1326786)', async (t) => {
const dataGrid = new DataGrid('#container');

await t.expect(dataGrid.isReady()).ok();
await t.expect(dataGrid.getScrollTop()).gt(0);
await t.expect(dataGrid.apiPageIndex()).eql(10);

const loadOptions = await getTestLoadOptions();

await t.expect(loadOptions).eql([{ skip: 1000, take: 100 }]);
}).before(async () => {
await ClientFunction(() => {
(window as any).testLoadOptions = [];
})();

return createWidget('dxDataGrid', () => ({
height: 1000,
remoteOperations: true,
renderAsync: false,
templatesRenderAsynchronously: true,
dataSource: new (window as any).DevExpress.data.CustomStore({
key: 'id',
load(loadOptions: any) {
(window as any).testLoadOptions.push({
skip: loadOptions.skip,
take: loadOptions.take,
});

const skip = loadOptions.skip ?? 0;
const take = loadOptions.take ?? 20;
const data: Record<string, unknown>[] = [];

for (let i = skip; i < skip + take; i += 1) {
data.push({ id: i, text: `item ${i}` });
}

return Promise.resolve({ data, totalCount: 5000 });
},
}),
scrolling: {
mode: 'virtual',
useNative: false,
},
paging: {
pageSize: 100,
pageIndex: 10,
},
columns: [
{ dataField: 'id', cellTemplate: 'cell' },
'text',
],
integrationOptions: {
templates: {
cell: {
render(e: any) {
setTimeout(() => {
($(e.container) as any).text(e.model.value);
e.onRendered?.();
});
},
},
},
},
}));
}).after(async () => ClientFunction(() => {
delete (window as any).testLoadOptions;
})());

fixture`Scrolling - warnings`
.page(url(__dirname, '../../container.html'));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1122,18 +1122,30 @@ export const data = (Base: ModuleType<DataController>) => class VirtualScrolling
}
}

private isViewportScrolledToPage(): boolean {
const initialPageScrollPending = isVirtualPaging(this)
&& this._rowsScrollController?.getViewportItemIndex() === 0
&& this.pageIndex() > 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the guard reads viewportItemIndex === 0 && pageIndex() > 0 as "the initial scroll hasn't happened yet" - are those two guaranteed to line up only at init? i'm thinking of a state restore or a focused-row scroll-into-view where pageIndex() is legitimately > 0 while the viewport still sits at item 0, or a refresh that briefly resets viewportItemIndex to 0 - would updateViewport then skip a load it actually needs, or does another path cover it?


return !initialPageScrollPending;
}

private updateViewport() {
const viewportSize = this.viewportSize();
const itemCount = this.items().length;
const viewportIsNotFilled = viewportSize > itemCount;
const currentTake = this._loadViewportParams?.take ?? 0;
const rowsScrollController = this._rowsScrollController;
const newTake = rowsScrollController?.getViewportParams().take;
const newTake = this._rowsScrollController?.getViewportParams().take ?? 0;

(viewportIsNotFilled || currentTake < newTake!) && !this._isPaging && itemCount && this.loadViewport({
checkLoading: true,
viewportIsNotFilled,
});
const needsMoreItems = viewportIsNotFilled || currentTake < newTake;
const canLoad = !this._isPaging && this.isViewportScrolledToPage(); // T1326786

if (needsMoreItems && canLoad && itemCount) {
this.loadViewport({
checkLoading: true,
viewportIsNotFilled,
});
}
}

private loadIfNeed() {
Expand Down
Loading