Vaadin 13: Prevent user from switching Tabs

Hi,

how to prevent a user from switching to a different com.vaadin.flow.component.tabs.Tab, incase he has unfinished Tasks to complete / unsaved changes.

If clicking the Tab means navigating to another view, then you could let your Tab Views implement BeforeLeaveObserver and prevent the navigation with beforeLeaveEvent.postpone(); if there are unsaved changes. Do make sure to let the user know why he can’t navigate (or give them the possibility to navigate anyway if they wish, with a confirmation dialog maybe). Please note that the beforeLeave method is not called when closing the browser, but only when internal routing events are used for navigation (RouterLink, ui.navigate()). Please read [this thread]
(https://vaadin.com/forum/thread/17523194/unsaved-changes-detect-page-exit-or-reload) if you want to prevent closing the browser / browser-tab too. The solution there is to use the beforeunload event from JavaScript.

If the other Tab content is within the same View, then implementing the BeforeLeaveObserver is not helping, because you are not leaving the view. You will have to add a clickListener to the tab and decide in there if you want to change tabs (check for changes / incomplete tasks). Another option there is to disable the tabs when starting changes / tasks, and enable them again upon saving / completing the tasks.

Hi Kaspar,

thanks for the quick response.
I can’t use option 1 since I’m not using routes as you already pointed out correctly.
I tried option 2 but I didn’t find a way to prevent the selection-changed event. So I had to reselect the last tab which leads to a short flickering of tabs.

When using option 3 the tabs don’t get “visually” reselected, when I set the selected tab programmatically

Example for option 3

@Route("test")
public class TestView extends VerticalLayout {

    private TextField exampleField;
    private Tabs tabs;
    private Tab lastSelectedTab;

    public TestView() {

        Map<Tab, Component> tabsToPages = new HashMap<>();

        Div pages = new Div();

        exampleField = new TextField("Example");
        exampleField.setReadOnly(false);
        Button start = new Button("Start  editing", e -> changeStatus(true));
        Button stop = new Button("Stop editing", e -> changeStatus(false));
        Div page1 = new Div(start, stop, exampleField);

        Div page2 = new Div();
        page2.setText("Page 2");

        pages.add(page1, page2);

        tabs = new Tabs();

        Tab tab1 = new Tab("tab index 0");
        Tab tab2 = new Tab("tab index 1");

        tabsToPages.put(tab1, page1);
        tabsToPages.put(tab2, page2);

        tabs.add(tab1);
        tabs.add(tab2);

        add(tabs, pages);
        tabs.addSelectedChangeListener(event -> {
            if (tabs.getSelectedTab() == null)
                return;
            pages.getChildren().forEach(page -> page.setVisible(false));
            tabsToPages.get(tabs.getSelectedTab()).setVisible(true);
            lastSelectedTab = tabs.getSelectedTab();
        });

        changeStatus(false);

    }

    private void changeStatus(boolean isEditing) {
        exampleField.setReadOnly(!isEditing);
        if (isEditing)
            tabs.setEnabled(false);
        else {
            tabs.setEnabled(true);
            tabs.setSelectedTab(lastSelectedTab);
        }
        Div status = new Div();
        status.setText("Editing status changed! Last selected tab index: " + tabs.getSelectedIndex());
        add(status);
    }
}

![Option 3 not working]
(https://s16.directupload.net/images/190418/fssprlgc.gif)

Without a Tabsheet class like in vaadin 8, I don’t see any advantages to Buttons (besides styling). The tab API would need a beforeSelectChange listener which can prevent the select from happening

this is where my knowledge ends, I don’t actually know how to prevent selection-changed event. Maybe other people here could help with that?

And about the visual reselection after enabling the tabs again, not sure here too but i think if you can manage to somehow call the Tabs’ private method updateSelectedTab(false) it should solve the issue. The problem is that this is private, and only called in constructor, add(), remove(), removeAll(), and replace(). maybe try to replace an existing tab with the same one? a little cheeky, but until there is a better option, if it works then it works.
(Or create your own Tabs class which extends the vaadins Tabs, make a copy of the updateSelectedTab() method and make it public?)

If you create a [github issue]
(https://github.com/vaadin/vaadin-tabs-flow/issues) for this, then the vaadin experts could have a look at it and hopefully provide us with a better solution / bugfix. Because that the selected tab is no longer visually selected after disabling and enabling it, is definitely a bug and needs to be fixed.

Thank you very much for your help. I’ll try to override the updateSelectedTab () behavior, otherwise I’ll probably create a github-issue