Skip to content

Commit 14a717a

Browse files
authored
T1260472: fix grid async render to avoid blinking (DevExpress#28972)
Co-authored-by: Vladimir Bushmanov <[email protected]>
1 parent 4768869 commit 14a717a

File tree

8 files changed

+107
-7
lines changed

8 files changed

+107
-7
lines changed
16.1 KB
Loading
5.61 KB
Loading

e2e/testcafe-devextreme/tests/dataGrid/virtualColumns.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,3 +358,85 @@ test('Group row should have right colspan with summary, virtual columns and fixe
358358
},
359359
});
360360
});
361+
362+
// T1260472
363+
test('Header, fixed columns and virtual scroll bar should have stable position during async render and virtual horizontal scrolling', async (t) => {
364+
const dataGrid = new DataGrid('#container');
365+
const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
366+
367+
await t.expect(dataGrid.getDataRow(0).element.exists).ok(); // wait for initial render
368+
await ClientFunction(() => { (window as any).deferred = $.Deferred(); })();
369+
await dataGrid.scrollTo(t, { x: 2000 });
370+
await takeScreenshot('T1260472-async-render-during-horizontal-scrolling.png', dataGrid.element);
371+
await ClientFunction(() => {
372+
(window as any).deferred.resolve();
373+
(window as any).deferred = undefined;
374+
})();
375+
await takeScreenshot('T1260472-async-render-after-horizontal-scrolling.png', dataGrid.element);
376+
377+
await t
378+
.expect(compareResults.isValid())
379+
.ok(compareResults.errorMessages());
380+
}).before(async () => {
381+
const defaultColumnConfig = {
382+
headerCellTemplate: 'headerCellTemplate',
383+
cellTemplate: 'cellTemplate',
384+
};
385+
386+
return createWidget('dxDataGrid', {
387+
dataSource: generateData(3, 50),
388+
keyExpr: 'field1',
389+
showBorders: true,
390+
width: 500,
391+
columnWidth: 100,
392+
scrolling: {
393+
rowRenderingMode: 'virtual',
394+
columnRenderingMode: 'virtual',
395+
mode: 'virtual',
396+
useNative: false,
397+
},
398+
columns: Array.from({ length: 20 }).map((_, i) => ({
399+
...defaultColumnConfig,
400+
caption: `Product${i + 1}`,
401+
fixed: i === 0,
402+
columns: [
403+
{ ...defaultColumnConfig, dataField: `field${(2 * i) + 1}`, fixed: i === 0 },
404+
{ ...defaultColumnConfig, dataField: `field${(2 * i) + 2}`, fixed: i === 0 },
405+
],
406+
})),
407+
// @ts-expect-error private option
408+
templatesRenderAsynchronously: true,
409+
integrationOptions: {
410+
templates: {
411+
headerCellTemplate: {
412+
render({ model, container, onRendered }) {
413+
const title = model.column.caption == null ? null : model.column.caption;
414+
const content = $(`<span title='${title}'>
415+
${title}
416+
</span>`);
417+
container.append(content);
418+
if ((window as any).deferred) {
419+
(window as any).deferred.done(onRendered);
420+
} else {
421+
onRendered();
422+
}
423+
},
424+
},
425+
cellTemplate: {
426+
render({ model, container, onRendered }) {
427+
const title = model.value == null ? null : model.value;
428+
const content = $(`<span title='${title}'>
429+
${title}
430+
</span>`);
431+
container.append(content);
432+
if ((window as any).deferred) {
433+
(window as any).deferred.done(onRendered);
434+
} else {
435+
onRendered();
436+
}
437+
},
438+
},
439+
},
440+
},
441+
});
442+
});

packages/devextreme/js/__internal/grids/data_grid/summary/m_summary.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ export class FooterView extends ColumnsView {
226226
this._updateContent(this._renderTable({ change }), change);
227227
needUpdateScrollLeft && this._updateScrollLeftPosition();
228228
}
229+
230+
return super._renderCore(change);
229231
}
230232

231233
protected _updateContent($newTable, change) {

packages/devextreme/js/__internal/grids/grid_core/column_headers/m_column_headers.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,7 @@ export class ColumnHeadersView extends ColumnsView {
299299

300300
$container
301301
.addClass(that.addWidgetPrefix(HEADERS_CLASS))
302-
.toggleClass(that.addWidgetPrefix(NOWRAP_CLASS), !that.option('wordWrapEnabled'))
303-
.empty();
302+
.toggleClass(that.addWidgetPrefix(NOWRAP_CLASS), !that.option('wordWrapEnabled'));
304303

305304
that.setAria('role', 'presentation', $container);
306305

packages/devextreme/js/__internal/grids/grid_core/sticky_columns/m_sticky_columns.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,7 @@ const baseStickyColumns = <T extends ModuleType<ColumnsView>>(Base: T) => class
127127
}
128128

129129
protected _renderCore(options?) {
130-
super._renderCore(options);
131-
130+
const deferred = super._renderCore(options);
132131
const $element = this.element();
133132
const hasStickyColumns = this.hasStickyColumns();
134133

@@ -137,6 +136,14 @@ const baseStickyColumns = <T extends ModuleType<ColumnsView>>(Base: T) => class
137136
hasStickyColumns,
138137
this.addWidgetPrefix.bind(this),
139138
);
139+
140+
if (hasStickyColumns) {
141+
return deferred.done(() => {
142+
this.setStickyOffsets();
143+
});
144+
}
145+
146+
return deferred;
140147
}
141148

142149
protected _createCell(options) {

packages/devextreme/js/__internal/grids/grid_core/views/m_columns_view.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,9 @@ export class ColumnsView extends ColumnStateMixin(modules.View) {
718718
if (!$root || $root.parent().length) {
719719
this.renderDelayedTemplates(e);
720720
}
721+
722+
// @ts-expect-error
723+
return new Deferred().resolve();
721724
}
722725

723726
/**
@@ -1119,6 +1122,9 @@ export class ColumnsView extends ColumnStateMixin(modules.View) {
11191122
return result.promise();
11201123
}
11211124

1125+
/**
1126+
* @extended: sticky_columns, rows_view
1127+
*/
11221128
protected _updateContent($newTableElement, change, isFixedTableRendering?) {
11231129
return this.waitAsyncTemplates().done(() => {
11241130
this._removeContent(isFixedTableRendering);

packages/devextreme/js/__internal/grids/grid_core/virtual_columns/m_virtual_columns.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,15 @@ const rowsView = (Base: ModuleType<RowsView>) => class VirtualColumnsRowsViewExt
5858
const $contentElement = this._findContentElement();
5959
const fixedColumns = this._columnsController?.getFixedColumns();
6060
const useNativeScrolling = this._scrollable?.option('useNative');
61+
const legacyMode = this.option('columnFixing.legacyMode');
6162

6263
if (fixedColumns?.length) {
63-
$contentElement.css({
64-
minHeight: useNativeScrolling ? getHeight($contentElement) : gridCoreUtils.getContentHeightLimit(browser),
65-
});
64+
// TODO: remove the condition when legacyMode is removed
65+
if (legacyMode && !useNativeScrolling) {
66+
$contentElement.css({ minHeight: gridCoreUtils.getContentHeightLimit(browser) });
67+
} else {
68+
$contentElement.css({ minHeight: getHeight($contentElement) });
69+
}
6670

6771
const resizeCompletedHandler = () => {
6872
this.resizeCompleted.remove(resizeCompletedHandler);

0 commit comments

Comments
 (0)