Skip to content
Draft
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
30 changes: 29 additions & 1 deletion packages/grid-pro/src/vaadin-grid-pro-inline-editing-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export const InlineEditingMixin = (superClass) =>
_disabledChanged(disabled, oldDisabled) {
super._disabledChanged(disabled, oldDisabled);

if (disabled && this.__edited) {
if (disabled) {
this._stopEdit(true);
}
}
Expand Down Expand Up @@ -330,6 +330,9 @@ export const InlineEditingMixin = (superClass) =>
if (this.__edited && !this.__edited.cell.isConnected) {
this._stopEdit(true, false);
}
if (this.__pendingEdit && !this.__pendingEdit.cell.isConnected) {
this.__pendingEdit = null;
}
}

/** @private */
Expand Down Expand Up @@ -357,10 +360,22 @@ export const InlineEditingMixin = (superClass) =>
_startEdit(cell, column) {
const isCellEditable = this._isCellEditable(cell);

// A new edit request supersedes any previously deferred one.
this.__pendingEdit = null;

// TODO: remove `_editingDisabled` after Flow counterpart is updated.
if (this.disabled || this._editingDisabled || !isCellEditable) {
return;
}

// A loading row has no item yet, so the editor can't be rendered against
// it. Defer the edit and resume it from `__updateRow` once the item has
// loaded. This can happen when committing an edit triggers clearCache()
// and the next cell's row is still loading.
if (cell.__parentRow.hasAttribute('loading')) {
this.__pendingEdit = { cell, column };
return;
}
// Cancel debouncer enqueued on focusout
this._cancelStopEdit();

Expand Down Expand Up @@ -391,6 +406,9 @@ export const InlineEditingMixin = (superClass) =>
* @protected
*/
_stopEdit(shouldCancel, shouldRestoreFocus) {
// Stopping supersedes a deferred edit start.
this.__pendingEdit = null;

if (!this.__edited) {
return;
}
Expand Down Expand Up @@ -552,6 +570,16 @@ export const InlineEditingMixin = (superClass) =>
}
}
super.__updateRow(row, item);

// Resume an edit that was deferred while the row was loading, now that
// the row has an item again.
if (this.__pendingEdit && item) {
const { cell, column } = this.__pendingEdit;
if (cell.__parentRow === row && this._isCellEditable(cell)) {
this.__pendingEdit = null;
this._startEdit(cell, column);
}
}
}

/**
Expand Down
3 changes: 2 additions & 1 deletion packages/grid-pro/test/keyboard-navigation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,8 @@ describe('keyboard navigation', () => {
// Normal behavior should call it once or twice at most
expect(stopEditSpy.callCount).to.be.lessThan(5);

// Verify the second cell is now in edit mode
// The next cell's row is loading after clearCache, so the edit is
// deferred and resumes once the item loads
const secondCell = getContainerCell(grid.$.items, 0, 1);
expect(getCellEditor(secondCell)).to.be.ok;
});
Expand Down
6 changes: 3 additions & 3 deletions packages/grid/src/vaadin-grid-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -773,18 +773,18 @@ export const GridMixin = (superClass) =>
* @private
*/
__updateRow(row) {
row._item = this.__getRowItem(row);

this.__a11yUpdateRowRowindex(row);
this.__updateRowOrderParts(row);

const item = this.__getRowItem(row);
if (item) {
if (row._item) {
this.__updateRowLoading(row, false);
} else {
this.__updateRowLoading(row, true);
return;
}

row._item = item;
const model = this.__getRowModel(row);

this._toggleDetailsCell(row, model.detailsOpened);
Expand Down
21 changes: 21 additions & 0 deletions packages/grid/test/activate-events.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ describe('activate events', () => {
expect(e.detail.model.item).to.be.ok;
});

it('should fire with undefined item on loading cell click', () => {
grid.dataProvider = () => {};
getBodyCellContent(grid, 0, 0).click();
expect(spy).to.be.calledOnce;

const e = spy.firstCall.args[0];
expect(e.detail.model.index).to.equal(0);
expect(e.detail.model.item).to.be.undefined;
});

it('should fire on cell Space', async () => {
await sendKeys({ press: 'Space' });
expect(spy).to.be.calledOnce;
Expand Down Expand Up @@ -91,6 +101,17 @@ describe('activate events', () => {
expect(e.detail.model.item).to.be.ok;
});

it('should fire with undefined item on loading row Space', async () => {
grid.dataProvider = () => {};
await sendKeys({ press: 'ArrowLeft' });
await sendKeys({ press: 'Space' });
expect(spy).to.be.calledOnce;

const e = spy.firstCall.args[0];
expect(e.detail.model.index).to.equal(0);
expect(e.detail.model.item).to.be.undefined;
});

it('should not fire on cell Space', async () => {
await sendKeys({ press: 'ArrowRight' });
await sendKeys({ press: 'Space' });
Expand Down
2 changes: 1 addition & 1 deletion packages/grid/test/scroll-to-index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ describe('scroll to index', () => {
}

function getFirstVisibleItemId() {
return getFirstVisibleItem(grid)._item.name;
return getFirstVisibleItem(grid)._item?.name;
}

beforeEach(async () => {
Expand Down
Loading