Navigator and back button

Hi everyone!

I’m having some issues with the
Navigator
in my app after using the browser back button. Let me explain the situation:

Our app has a login page and some “logged in” pages, nothing fancy. The only “weird” thing is that the login page has a different layout than the “logged in” pages. Let me clarify this:

Login page:

[font=courier new]

    -------------------
    |     Login view   |
    -------------------

[/font]

“Logged in” pages:

[font=courier new]

      |

Menu | Content
|

[/font]

In the “logged in” pages, the “content” view is the one passed to the
Navigator
as a
ComponentContainer
. In the login page, as we don’t follow the same layout, is the
UI
what is passed to the
Navigator
as the
ComponentContainer
.

Something like this is being done on the
init()
of the
UI
:

[code]
@Override
protected void init(VaadinRequest request) {
Navigator navigator = new Navigator(this, this);

navigator.addView(“login”, LoginView.class);
navigator.navigateTo(“login”);
}
[/code]Later on, after a successful login:

[code]
// Custom View for the Layout
NavigationView navigationView = new NavigationView();
UI.getCurrent().setContent(navigationView);

Navigator navigator = new Navigator(this, navigationView.getContentView());
AppUI.getCurrentApp().setNavigator(navigator);

navigator.addView(“home”, HomeView.class);
navigator.addView(“another”, AnotherView.class);

navigator.navigateTo(“home”);
[/code]Ok, what is happening after doing this is (step by step):

  • Access page, login view is loaded
  • Successful login, redirect to home view
  • From home view, click on link which redirects to “another” view
  • Press browser back button. Get error:
    “Trying to navigate to an unknown state ‘home’ and an error view provider not present”

Do you know what could be happening?

Thank you so much for your time!

Hi, it looks like first navigator is still in use.

How do you navigate from “login” to “logged in”? It seems useless to have one navigator with only one page.

What is AppUI.getCurrentApp() providing? Once you create a Navigator it sets itself on the UI so you can later retrive the navigator directly from UI.

Although it seems you can use more then one Navigator in your app, I wouldn’t recommend that. Which of them should listen to back and forth?

When you create a navigator with, maybe, the most used constructor Navigator(UI, SingleComponentContainer), the navigator will get it’s stateManager field set with an instance of UriFragmentManager, which is also a UriFragmentChangedListener. UriFragmentManager will add itself to the page uri change event listeners. If you have 2 navigators you have to listeners notified when the uri fragment change, in the order you added them. So when you go back to “home”, the listener to be notified first is the one from the first navigator, thus the error you get, because ther’s no “home” there. It’s only “login”.

But if you really want to use more navigators, either you provide your own NavigationStateManager or remove the UriFragmentChangedListener from the UI’s page when create another Navigator, which is a bit nasty because you need to extend Navigator to make getStateManager public (it’s protected), or use reflection to make it accessible, then cast it to UriFragmentChangeListener. Something like this:

            ui.getPage().removeUriFragmentChangedListener(
                    (UriFragmentChangedListener) ((Navigator2) ui
                            .getNavigator()).getStateManager());

            // Then you can safely do this.
            Navigator navigator = new Navigator(ui,
                    navigationView.getContentView());

Eventually you can submit a ticket about this, because the API is not clear and should be fixed, maybe limited.

Thanks a lot for your answer. Very clear, makes a lot of sense :slight_smile: