Reputation: 61
I am getting this exception in my Vaadin app when I try to hide a tab and set the selected tab to the correct one.
I'm using Spring and everything is marked as @UIScope in the config.
I have been looking at this for days and am struggling to work out the issue. What I do know is removing @PreserveOnRefresh fixes it but I need this as well....
I'm using Vaadin 22.0.28
My code looks like this:
@PageTitle("Instruments")
@Route(value = "instrument", layout = MainView.class)
@RouteAlias(value = "", layout = MainView.class)
@CssImport("./views/instrument/instrument-tabs-view.css")
@PreserveOnRefresh
public class InstrumentTabsView extends VerticalLayout {
private final Map<Tab, Component> tabsComponentCache = new HashMap<>();
private final Tab cmdTab = new Tab(getTranslation(T_CMD));
private final Tab crTab = new Tab(getTranslation(T_CR));
private final Tabs tabs = new Tabs();
private Component grid;
private final Supplier<Universe> universeSupplier;
public InstrumentTabsView(@Autowired CmdInstrumentsGridView cmdInstrumentsGridView,
@Autowired CrInstrumentsGridView crInstrumentsGridView,
@Autowired Supplier<Universe> universeSupplier) {
this.universeSupplier = universeSupplier;
setSizeFull();
tabsComponentCache.put(cmdTab, cmdInstrumentsGridView);
tabsComponentCache.put(crTab, crInstrumentsGridView);
grid = cmdInstrumentsGridView;
tabs.add(cmdTab, crTab);
setAppropriateTabs();
tabs.addClassName("assetClassTabs");
tabs.addSelectedChangeListener(event -> {
Component newGrid = tabsComponentCache.get(event.getSelectedTab());
replace(grid, newGrid); // <- error thrown here
grid = newGrid;
});
add(tabs, grid);
addAttachListener(e -> {
((BaseGridView) grid).refreshGrid();
setAppropriateTabs();
});
}
private void setAppropriateTabs() {
Universe universe = universeSupplier.get();
if (universe != null && UniverseType.VAR.equals(universe.getType())) {
cmdTab.setVisible(false);
setSelectedTab(AssetClass.CR);
}
else {
cmdTab.setVisible(true);
setSelectedTab(AssetClass.CMD);
}
}
public void setSelectedTab(AssetClass assetClass) {
Tab selectedTab;
switch (assetClass) {
case CMD:
selectedTab = cmdTab;
break;
case CR:
selectedTab = crTab;
break;
default:
selectedTab = null;
break;
}
tabs.setSelectedTab(selectedTab);
}
}
The page is refreshed when a drop down in the MainView changes which calls
getUI().ifPresent(ui -> ui.getPage().reload());
I have tried to see where in the Vaadin code the issue is and it seems to be the StateNode.class in this method where isOwnerAttached resolves as true.
private void doSetTree(StateTree tree) {
if (tree != this.getOwner()) {
if (this.getOwner() instanceof StateTree) {
boolean isOwnerAttached = ((StateTree)this.getOwner()).getRootNode().isAttached();
boolean isNotReplaced = ComponentUtil.getData(((StateTree)this.getOwner()).getUI(), ReplacedViaPreserveOnRefresh.class) == null;
if (isOwnerAttached || isNotReplaced) {
throw new IllegalStateException("Can't move a node from one state tree to
another. If this is intentional, first remove the node from its current state tree by calling removeFromTree");
}
this.id = -1;
}
this.owner = tree;
}
}
Upvotes: 0
Views: 133
Reputation: 4290
I feel like the problem is rooted in your private final Map<Tab, Component> tabsComponentCache = new HashMap<>();
. When you're using @PreserveOnRefresh
, the component with the annotation is switched over to the new UI and new state tree when you refresh. I presume the components in the Map are still in the old state tree (maybe they're not direct children of the annotated component?), and thus you're getting the exception. You should probably clear the Map when the root view component is detached. I'd also evaluate the use of the tabsComponentCache
, it feels like an anti-pattern (but I can't confirm that with the given information).
Upvotes: 0