diff --git a/vaadin-grid-flow-integration-tests/src/main/java/com/vaadin/flow/component/grid/it/GridOnClientAndSlotPage.java b/vaadin-grid-flow-integration-tests/src/main/java/com/vaadin/flow/component/grid/it/GridOnClientAndSlotPage.java index 1bcbd56e..a468ccf1 100644 --- a/vaadin-grid-flow-integration-tests/src/main/java/com/vaadin/flow/component/grid/it/GridOnClientAndSlotPage.java +++ b/vaadin-grid-flow-integration-tests/src/main/java/com/vaadin/flow/component/grid/it/GridOnClientAndSlotPage.java @@ -2,18 +2,27 @@ import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.html.NativeButton; import com.vaadin.flow.router.Route; @Route("grid-on-client-and-slot") public class GridOnClientAndSlotPage extends Div { public GridOnClientAndSlotPage() { GridOnClientAndSlot gridOnClientAndSlot = new GridOnClientAndSlot(); + + gridOnClientAndSlot.add(createGrid()); + + NativeButton addGridButton = new NativeButton("add grid", e -> gridOnClientAndSlot.add(createGrid())); + addGridButton.setId("add-new-grid-button"); + + add(gridOnClientAndSlot, addGridButton); + } + + private Grid createGrid() { Grid grid = new Grid<>(); grid.addColumn(String::toString).setHeader("Column"); grid.setItems("Item 1", "Item 2", "Item 3", "Item 4"); - - gridOnClientAndSlot.add(grid); - add(gridOnClientAndSlot); + return grid; } } diff --git a/vaadin-grid-flow-integration-tests/src/test/java/com/vaadin/flow/component/grid/it/GridOnClientAndServerIT.java b/vaadin-grid-flow-integration-tests/src/test/java/com/vaadin/flow/component/grid/it/GridOnClientAndServerIT.java index f868702f..b8126b7e 100644 --- a/vaadin-grid-flow-integration-tests/src/test/java/com/vaadin/flow/component/grid/it/GridOnClientAndServerIT.java +++ b/vaadin-grid-flow-integration-tests/src/test/java/com/vaadin/flow/component/grid/it/GridOnClientAndServerIT.java @@ -17,6 +17,7 @@ import org.junit.Assert; import org.junit.Test; +import org.openqa.selenium.By; import com.vaadin.flow.component.grid.testbench.GridTHTDElement; import com.vaadin.flow.component.grid.testbench.TreeGridElement; @@ -34,9 +35,15 @@ public void treeGridOnClientShouldWorkIfAnotherGridIsAddedFromServer() { TestBenchElement parent = $("grid-on-client-and-slot").first(); TreeGridElement treeGrid = parent.$(TreeGridElement.class).id("tree"); - treeGrid.getExpandToggleElement(0, 0).click();; + treeGrid.getExpandToggleElement(0, 0).click(); GridTHTDElement cell = treeGrid.getCell(1, 0); Assert.assertEquals("child 1-1", cell.getText().trim()); + + findElement(By.id("add-new-grid-button")).click(); + treeGrid.getExpandToggleElement(3, 0).click(); + cell = treeGrid.getCell(4, 0); + + Assert.assertEquals("child 2-1", cell.getText().trim()); } } diff --git a/vaadin-grid-flow/src/main/resources/META-INF/resources/frontend/gridConnector.js b/vaadin-grid-flow/src/main/resources/META-INF/resources/frontend/gridConnector.js index b3349c12..2c2e619b 100644 --- a/vaadin-grid-flow/src/main/resources/META-INF/resources/frontend/gridConnector.js +++ b/vaadin-grid-flow/src/main/resources/META-INF/resources/frontend/gridConnector.js @@ -8,6 +8,8 @@ import { ItemCache } from '@vaadin/vaadin-grid/src/vaadin-grid-data-provider-mix return window.Vaadin.Flow.tryCatchWrapper(callback, 'Vaadin Grid', 'vaadin-grid-flow'); }; + let isItemCacheInitialized = false; + window.Vaadin.Flow.gridConnector = { initLazy: grid => tryCatchWrapper(function(grid) { // Check whether the connector was already initialized for the grid @@ -15,60 +17,65 @@ import { ItemCache } from '@vaadin/vaadin-grid/src/vaadin-grid-data-provider-mix return; } - // Storing original implementation of the method to be used for client - // side only grids - ItemCache.prototype.ensureSubCacheForScaledIndexOriginal = ItemCache.prototype.ensureSubCacheForScaledIndex; - ItemCache.prototype.ensureSubCacheForScaledIndex = tryCatchWrapper(function(scaledIndex) { - if (!this.grid.$connector) { - this.ensureSubCacheForScaledIndexOriginal(scaledIndex); - return; - } + // Make sure ItemCache patching is done only once, but delay it for when + // a server grid is initialized + if (!isItemCacheInitialized) { + isItemCacheInitialized = true; + // Storing original implementation of the method to be used for client + // side only grids + ItemCache.prototype.ensureSubCacheForScaledIndexOriginal = ItemCache.prototype.ensureSubCacheForScaledIndex; + ItemCache.prototype.ensureSubCacheForScaledIndex = tryCatchWrapper(function(scaledIndex) { + if (!this.grid.$connector) { + this.ensureSubCacheForScaledIndexOriginal(scaledIndex); + return; + } - if (!this.itemCaches[scaledIndex]) { - this.grid.$connector.beforeEnsureSubCacheForScaledIndex(this, scaledIndex); - } - }) + if (!this.itemCaches[scaledIndex]) { + this.grid.$connector.beforeEnsureSubCacheForScaledIndex(this, scaledIndex); + } + }); - ItemCache.prototype.doEnsureSubCacheForScaledIndex = tryCatchWrapper(function(scaledIndex) { - if (!this.itemCaches[scaledIndex]) { - const subCache = new ItemCache.prototype.constructor(this.grid, this, this.items[scaledIndex]); - subCache.itemkeyCaches = {}; - if(!this.itemkeyCaches) { - this.itemkeyCaches = {}; + ItemCache.prototype.doEnsureSubCacheForScaledIndex = tryCatchWrapper(function(scaledIndex) { + if (!this.itemCaches[scaledIndex]) { + const subCache = new ItemCache.prototype.constructor(this.grid, this, this.items[scaledIndex]); + subCache.itemkeyCaches = {}; + if(!this.itemkeyCaches) { + this.itemkeyCaches = {}; + } + this.itemCaches[scaledIndex] = subCache; + this.itemkeyCaches[this.grid.getItemId(subCache.parentItem)] = subCache; + this.grid._loadPage(0, subCache); } - this.itemCaches[scaledIndex] = subCache; - this.itemkeyCaches[this.grid.getItemId(subCache.parentItem)] = subCache; - this.grid._loadPage(0, subCache); - } - }) + }); - ItemCache.prototype.getCacheAndIndexByKey = tryCatchWrapper(function(key) { - for (let index in this.items) { - if(grid.getItemId(this.items[index]) === key) { - return {cache: this, scaledIndex: index}; + ItemCache.prototype.getCacheAndIndexByKey = tryCatchWrapper(function(key) { + for (let index in this.items) { + if(this.grid.getItemId(this.items[index]) === key) { + return {cache: this, scaledIndex: index}; + } } - } - const keys = Object.keys(this.itemkeyCaches); - for (let i = 0; i < keys.length; i++) { - const expandedKey = keys[i]; - const subCache = this.itemkeyCaches[expandedKey]; - let cacheAndIndex = subCache.getCacheAndIndexByKey(key); - if(cacheAndIndex) { - return cacheAndIndex; + const keys = Object.keys(this.itemkeyCaches); + for (let i = 0; i < keys.length; i++) { + const expandedKey = keys[i]; + const subCache = this.itemkeyCaches[expandedKey]; + let cacheAndIndex = subCache.getCacheAndIndexByKey(key); + if(cacheAndIndex) { + return cacheAndIndex; + } } - } - return undefined; - }) + return undefined; + }); - ItemCache.prototype.getLevel = tryCatchWrapper(function() { - let cache = this; - let level = 0; - while (cache.parentCache) { - cache = cache.parentCache; - level++; - } - return level; - }) + ItemCache.prototype.getLevel = tryCatchWrapper(function() { + let cache = this; + let level = 0; + while (cache.parentCache) { + cache = cache.parentCache; + level++; + } + return level; + }); + } const rootPageCallbacks = {}; const treePageCallbacks = {};