0

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:

enter image description here

@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();
    }
}
euraad
  • 2,467
  • 5
  • 30
  • 51

1 Answers1

2

One bug related to this was fixed in Vaadin 14.2.1.

Erik Lumme
  • 5,202
  • 13
  • 27
  • I have Vaadin 14.2.1 and the error still appears. Notice that I have some static fields that are displayed at the layout. – euraad Jun 15 '20 at 16:47
  • Hej Erik! Jag har skapat två minimala Java exempel åt dig som du kan köra. :) – euraad Jun 15 '20 at 17:22
  • 1
    I'm afraid Vaadin does not support storing components in static fields, as this would mean it belongs to multiple UIs and could be modified by multiple users at the same time. Try to just store the data in the static field, if you want all users to see the same data, and re-build the component for every visitor. – Erik Lumme Jun 16 '20 at 13:49
  • 1
    As long the thread can run meanwhile the web browser is off, then I think I can have the plot and its settings as public and not static. – euraad Jun 16 '20 at 19:05