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
… (#7168)
  • Loading branch information
vursen committed Mar 5, 2024
1 parent e185bd3 commit 0ba4986
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 12 deletions.
30 changes: 20 additions & 10 deletions packages/grid/src/vaadin-grid.js
Expand Up @@ -535,18 +535,28 @@ class Grid extends ElementMixin(
}
}

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

/** @protected */
__itemsReceived() {
if (
this._recalculateColumnWidthOnceLoadingFinished &&
!this._cache.isLoading() &&
this.__hasRowsWithClientHeight()
) {
if (!this._recalculateColumnWidthOnceLoadingFinished || this._cache.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._recalculateColumnWidthOnceLoadingFinished = false;
this.recalculateColumnWidths();
}
Expand Down
36 changes: 34 additions & 2 deletions packages/grid/test/column-auto-width.test.js
@@ -1,5 +1,5 @@
import { expect } from '@esm-bundle/chai';
import { fixtureSync, nextFrame, oneEvent } from '@vaadin/testing-helpers';
import { aTimeout, fixtureSync, nextFrame, oneEvent } from '@vaadin/testing-helpers';
import sinon from 'sinon';
import '../vaadin-grid.js';
import '../vaadin-grid-column-group.js';
Expand Down Expand Up @@ -240,7 +240,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 @@ -264,6 +264,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.called).to.be.false;
await aTimeout(0);
expect(recalculateColumnWidthsSpy.calledOnce).to.be.true;
});
});
});

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

0 comments on commit 0ba4986

Please sign in to comment.