Why does I get this error when I close the tab in my web browser and go back to the same URL page again?
Error:
java.lang.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
Cause:
In this case, it's about Vaadin 14 where I'm using the AppLayout
class to set its components.
HorizontalLayout firstRow = new HorizontalLayout(loggerId, calibration, alarm, showSamples, samplingTime);
HorizontalLayout secondRow = new HorizontalLayout(do0SliderLayout, do1SliderLayout, do2SliderLayout, do3SliderLayout);
HorizontalLayout thirdRow = new HorizontalLayout(updatePlot, loggingActivate);
thirdRow.setAlignItems(Alignment.CENTER);
VerticalLayout layout = new VerticalLayout(firstRow, secondRow, thirdRow, apexChart);
setContent(layout);
Suggestion:
I think I need to clean up the content before I can set the layout again?
Question:
Do you know how to remove the node from state tree to another?
How to reproduce the error:
Copy over this to your IDE and run the code with Vaadin 14. Access the route, then close your web browser. Open your web browser again and access the route again. This code is a minimal example. I have removed so much I can.
The you will have this error:
@Route("")
@CssImport("./styles/shared-styles.css")
@CssImport(value = "./styles/vaadin-text-field-styles.css", themeFor = "vaadin-text-field")
@Push
@PreserveOnRefresh
public class MainView extends AppLayout {
/**
*
*/
private static final long serialVersionUID = 1L;
public static final String START_LOGGING = "Start logging";
public static final String STOP_LOGGING = "Stop logging";
static public Boolean selectedUpdatePlot = false;
static public Integer selectedShowSamples = 10; // Minimum
static public Integer selectedSamplingTime = 0;
static public Long selectedAID = 0L;
static public Long selectedCID = 0L;
static public Long selectedLoggerId = 0L;
static public ApexCharts apexChart;
static public PaperSlider do0Slider;
static public PaperSlider do1Slider;
static public PaperSlider do2Slider;
static public PaperSlider do3Slider;
static public AtomicBoolean loggingNow;
static public ControlThread control;
@PostConstruct
public void init() {
// Set the top and the tabs
Top top = new Top();
top.setTopAppLayout(this);
// Set the chart
if(apexChart == null)
apexChart = new Graf().getApexChart();
// Create layout for slider 0
if(do0Slider == null) {
do0Slider = new PaperSlider(4095);
}
// Create layout for slider 1
if(do1Slider == null) {
do1Slider = new PaperSlider(4095);
}
// Create layout for slider 2
if(do2Slider == null) {
do2Slider = new PaperSlider(4095);
}
// Create layout for slider 3
if(do3Slider == null) {
do3Slider = new PaperSlider(4095);
}
// This variable controls the logging thread
if(loggingNow == null) {
loggingNow = new AtomicBoolean();
}
// Create control panel
updateControlPanel();
// Start the tread
if(control == null) {
control = new ControlThread(UI.getCurrent());
control.start();
}
}
private void updateControlPanel() {
// Set the logger ids
List<UserLogg> userLoggers = new ArrayList<Long>();
Select<Long> loggerId = new Select<>();
ArrayList<Long> loggerIds = new ArrayList<Long>();
loggerIds.add(selectedLoggerId);
for(int i = 0; i < userLoggers.size(); i++) {
loggerIds.add(userLoggers.get(i).getLoggerId());
}
loggerId.setItems(loggerIds);
loggerId.setValue(selectedLoggerId);
loggerId.addValueChangeListener(e -> {
selectedLoggerId = loggerId.getValue();
});
// Set the calibration id
List<CalibrationLogg> calibrationsLoggers = new ArrayList<Long>();
Select<Long> calibration = new Select<>();
ArrayList<Long> CIDs = new ArrayList<Long>();
CIDs.add(selectedCID);
for(int i = 0; i < calibrationsLoggers.size(); i++) {
CIDs.add(calibrationsLoggers.get(i).getCID());
}
calibration.setItems(CIDs);
calibration.setValue(selectedCID);
calibration.addValueChangeListener(e -> {
selectedCID = calibration.getValue();
});
// Set the alarm id
List<AlarmLogg> alarmsLoggers = new ArrayList<Long>();
Select<Long> alarm = new Select<>();
ArrayList<Long> AIDs = new ArrayList<Long>();
AIDs.add(selectedAID);
for(int i = 0; i < alarmsLoggers.size(); i++) {
AIDs.add(alarmsLoggers.get(i).getAID());
}
alarm.setItems(AIDs);
alarm.setValue(selectedAID);
alarm.addValueChangeListener(e -> {
selectedAID = alarm.getValue();
});
// Slider 0
VerticalLayout do0SliderLayout = new VerticalLayout(new Label("DO0"), do0Slider);
do0SliderLayout.setAlignItems(Alignment.CENTER);
do0Slider.setEnabled(false);
// Slider 1
VerticalLayout do1SliderLayout = new VerticalLayout(new Label("DO1"), do1Slider);
do1SliderLayout.setAlignItems(Alignment.CENTER);
do1Slider.setEnabled(false);
// Slider 2
VerticalLayout do2SliderLayout = new VerticalLayout(new Label("DO2"), do2Slider);
do2SliderLayout.setAlignItems(Alignment.CENTER);
do2Slider.setEnabled(false);
// Slider 3
VerticalLayout do3SliderLayout = new VerticalLayout(new Label("DO3"), do3Slider);
do3SliderLayout.setAlignItems(Alignment.CENTER);
do3Slider.setEnabled(false);
// Sampling time for the thread
IntegerField samplingTime = new IntegerField();
samplingTime.setValue(selectedSamplingTime);
samplingTime.addValueChangeListener(e -> {
if(e.getValue() < 10) {
samplingTime.setValue(10);
selectedSamplingTime = 10;
}
selectedSamplingTime = samplingTime.getValue();
});
// Show amount of samples at the plot
Select<Integer> showSamples = new Select<Integer>();
showSamples.setItems(new Integer[] {10, 20, 30, 40, 50});
showSamples.setValue(selectedShowSamples);
showSamples.addValueChangeListener(e -> {
selectedShowSamples = showSamples.getValue();
});
// Check box if we want to show the plot or not
Checkbox updatePlot = new Checkbox();
updatePlot.setLabel("Plot");
updatePlot.setValue(selectedUpdatePlot);
updatePlot.addValueChangeListener(e -> {
selectedUpdatePlot = updatePlot.getValue();
});
// Start and stop button for logging
Button loggingActivate = new Button(START_LOGGING);
if(loggingNow.get() == true)
loggingActivate.setText(STOP_LOGGING);
loggingActivate.addClickListener(e -> {
if(loggingNow.get() == false) {
loggingActivate.setText(STOP_LOGGING);
calibration.setEnabled(false);
alarm.setEnabled(false);
loggerId.setEnabled(false);
do0Slider.setEnabled(true);
do1Slider.setEnabled(true);
do2Slider.setEnabled(true);
do3Slider.setEnabled(true);
samplingTime.setEnabled(false);
showSamples.setEnabled(false);
updatePlot.setEnabled(false);
loggingNow.set(true);
}else{
loggingActivate.setText(START_LOGGING);
calibration.setEnabled(true);
alarm.setEnabled(true);
loggerId.setEnabled(true);
do0Slider.setEnabled(false);
do1Slider.setEnabled(false);
do2Slider.setEnabled(false);
do3Slider.setEnabled(false);
samplingTime.setEnabled(true);
showSamples.setEnabled(true);
updatePlot.setEnabled(true);
loggingNow.set(false);
do0Slider.setValue(0);
do1Slider.setValue(0);
do2Slider.setValue(0);
do3Slider.setValue(0);
}
});
// Layout
HorizontalLayout firstRow = new HorizontalLayout(loggerId, calibration, alarm, showSamples, samplingTime);
HorizontalLayout secondRow = new HorizontalLayout(do0SliderLayout, do1SliderLayout, do2SliderLayout, do3SliderLayout);
HorizontalLayout thirdRow = new HorizontalLayout(updatePlot, loggingActivate);
thirdRow.setAlignItems(Alignment.CENTER);
VerticalLayout layout = new VerticalLayout(firstRow, secondRow, thirdRow, apexChart);
setContent(layout);
}
}
And a thread
public class ControlThread extends Thread{
private UI ui;
public ControlThread(UI ui) {
this.ui = ui;
}
@Override
public void run() {
while(true) {
}
}
}
Update:
Here is a very minimal code example. I'm using Vaadin 14.2.1 with OpenJDK 11
@Route("test")
@CssImport("./styles/shared-styles.css")
@CssImport(value = "./styles/vaadin-text-field-styles.css", themeFor = "vaadin-text-field")
public class TestView extends AppLayout {
/**
*
*/
private static final long serialVersionUID = 1L;
static public PaperSlider do0Slider;
@PostConstruct
public void init() {
// Set the slider
if(do0Slider == null) {
do0Slider = new PaperSlider(4095);
}
setContent(do0Slider);
}
}
And the paper-slider from Vaadin dev team.
@Tag("paper-slider")
@NpmPackage(value = "@polymer/paper-slider",
version = "3.0.1")
@JsModule("@polymer/paper-slider/paper-slider.js")
public class PaperSlider extends AbstractSinglePropertyField<PaperSlider, Integer> {
/**
*
*/
private static final long serialVersionUID = 1L;
public PaperSlider(int max) {
super("value", 0, false);
this.getElement().setProperty("max", max);
this.getElement().setProperty("pin", true);
}
}
Notice that if I use this test example:
@Route("test")
@CssImport("./styles/shared-styles.css")
@CssImport(value = "./styles/vaadin-text-field-styles.css", themeFor = "vaadin-text-field")
public class TestView extends AppLayout {
/**
*
*/
private static final long serialVersionUID = 1L;
static public ApexCharts apexChart;
@PostConstruct
public void init() {
// Set the chart
if(apexChart == null)
apexChart = new Graf().getApexChart();
setContent(apexChart);
}
}
With the plot class. I know that Apex Chart's is a third library for Vaadin. But it gives the same error as Paper-Slider.
@Data
public class Graf {
private ApexCharts apexChart;
private XAxis xAxis;
public Graf() {
apexChart = ApexChartsBuilder.get()
.withChart(ChartBuilder.get()
.withType(Type.line)
.withZoom(ZoomBuilder.get()
.withEnabled(true)
.build())
.withToolbar(ToolbarBuilder.get()
.withShow(true)
.build())
.withAnimations(AnimationsBuilder.get()
.withEnabled(false)
.build())
.build())
.withLegend(LegendBuilder.get()
.withShow(true)
.build())
.withDataLabels(DataLabelsBuilder.get()
.withEnabled(false)
.build())
.withColors("#48912c", "#13ebd5", "#215ed9", "#e6c222", "#a524e0", "#633326") // PWM1, PWM2, PMW4, Temp1, Temp2
.withTooltip(TooltipBuilder.get()
.withEnabled(false)
.build())
.withStroke(StrokeBuilder.get()
.withCurve(Curve.straight)
.build())
.withTitle(TitleSubtitleBuilder.get()
.withText("MySQL")
.withAlign(Align.left)
.build())
.withGrid(GridBuilder.get()
.withRow(RowBuilder.get()
.withColors("#f3f3f3", "transparent")
.withOpacity(0.5)
.build())
.build())
.withYaxis(YAxisBuilder.get()
.withTitle(TitleBuilder.get()
.withText("Measurements")
.build())
.build())
.withXaxis(XAxisBuilder.get()
.withTitle(com.github.appreciated.apexcharts.config.xaxis.builder.TitleBuilder.get()
.withText("Time")
.build())
.withCategories("")
.build())
.withSeries(new Series<>("desktop", 1, 2, 3))
.build();
apexChart.setWidthFull();
}
}