Skip to content

Commit

Permalink
fix: delay column width recalculation until all rows have index (#7165)
Browse files Browse the repository at this point in the history
  • Loading branch information
vursen authored Mar 5, 2024
1 parent 18b541b commit 3464cf2
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 12 deletions.
31 changes: 20 additions & 11 deletions packages/grid/src/vaadin-grid-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,11 +316,6 @@ export const GridMixin = (superClass) =>
}
}

/** @private */
__hasRowsWithClientHeight() {
return !!Array.from(this.$.items.children).filter((row) => row.clientHeight).length;
}

/** @private */
__getIntrinsicWidth(col) {
if (!this.__intrinsicWidthCache.has(col)) {
Expand Down Expand Up @@ -498,12 +493,26 @@ export const GridMixin = (superClass) =>

/** @private */
__tryToRecalculateColumnWidthsIfPending() {
if (
this.__pendingRecalculateColumnWidths &&
!isElementHidden(this) &&
!this._dataProviderController.isLoading() &&
this.__hasRowsWithClientHeight()
) {
if (!this.__pendingRecalculateColumnWidths || isElementHidden(this) || this._dataProviderController.isLoading()) {
return;
}

// Delay recalculation if any rows are missing an index.
// This can happen during the grid's initialization if the recalculation is triggered
// as a result of the data provider responding synchronously to a page request created
// in the middle of the virtualizer update loop. In this case, rows after the one that
// triggered the page request may not have an index property yet. The lack of index
// prevents _onDataProviderPageReceived from requesting children for these rows,
// resulting in loading state being set to false and the recalculation beginning
// before all the data is loaded. Note, rows without index get updated in later iterations
// of the virtualizer update loop, ensuring the grid eventually reaches a stable state.
const hasRowsWithUndefinedIndex = [...this.$.items.children].some((row) => row.index === undefined);
if (hasRowsWithUndefinedIndex) {
return;
}

const hasRowsWithClientHeight = [...this.$.items.children].some((row) => row.clientHeight > 0);
if (hasRowsWithClientHeight) {
this.__pendingRecalculateColumnWidths = false;
this.recalculateColumnWidths();
}
Expand Down
34 changes: 33 additions & 1 deletion packages/grid/test/column-auto-width.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ describe('async recalculateWidth columns', () => {
`);
});

it('should recalculate column widths when child items loaded', () => {
it('should recalculate column widths when child items are loaded synchronously', () => {
const data = [
{
name: 'foo',
Expand All @@ -339,6 +339,38 @@ describe('async recalculateWidth columns', () => {
flushGrid(grid);
expect(grid._recalculateColumnWidths.called).to.be.true;
});

describe('initially empty grid', () => {
let recalculateColumnWidthsSpy, dataProvider;

beforeEach(() => {
recalculateColumnWidthsSpy = sinon.spy(grid, 'recalculateColumnWidths');
dataProvider = (_params, callback) => callback([], 0);
grid.dataProvider = (params, callback) => dataProvider(params, callback);
flushGrid(grid);
recalculateColumnWidthsSpy.resetHistory();
});

it('should recalculate column widths when child items are loaded asynchonously', async () => {
const items = [{ name: 'Item-0' }, { name: 'Item-1', children: [{ name: 'Item-1-0' }] }];

dataProvider = ({ parentItem }, callback) => {
if (parentItem) {
setTimeout(() => callback(parentItem.children, parentItem.children.length));
} else {
callback(items.slice(0, grid.size), grid.size);
}
};

grid.expandItem(items[1]);
grid.size = 2;
flushGrid(grid);

expect(recalculateColumnWidthsSpy).to.be.not.called;
await aTimeout(0);
expect(recalculateColumnWidthsSpy).to.be.calledOnce;
});
});
});

describe('column group', () => {
Expand Down

0 comments on commit 3464cf2

Please sign in to comment.