Dynamic routes

Hi,

I would like to add some dynamic routes. I have read the doc https://vaadin.com/docs/flow/routing/tutorial-router-dynamic-routes.html but I cannot get it working.
When doing: RouteConfiguration.forSessionScope().configuration.setRoute( "main", MyRoute.class );
I get an error: com.vaadin.flow.server.AmbiguousRouteConfigurationException: Navigation targets must have unique routes, found navigation targets '....MyRoute' and '....MyRoute' with the same route.

My goal is to have onw class which can serve multiple pages.
for now I have got in my AppLayout constructor:

public class MyRoute extends Div
{
}

public class MainLayout extends AppLayout implements RouterLayout

  public MainLayout()
  {
    ...
	
    RouteConfiguration configuration = RouteConfiguration.forSessionScope();
    configuration.setRoute( "main", MyRoute.class );
    configuration.setRoute( "info", MyRoute.class );
    configuration.setRoute( "version", MyRoute.class );

    addToDrawer( createMenuLink( MyRoute.class, "Main", VaadinIcon.ALARM.create() ) );
    addToDrawer( createMenuLink( MyRoute.class, "Info", VaadinIcon.INFO.create() ) );
    addToDrawer( createMenuLink( MyRoute.class, "Version", VaadinIcon.QUESTION.create() ) );
  }
  
  private RouterLink createMenuLink( Class<? extends Component> viewClass, String caption, Icon icon )
  {
    final RouterLink routerLink = new RouterLink( null, viewClass );
    routerLink.setClassName( "menu-link" );
    routerLink.add( icon );
    routerLink.add( new Span( caption ) );
    icon.setSize( "24px" );
    return routerLink;
  }  
}

How can I make this working? And how can the class ‘MyRoute’ know if it must show ‘main’, ‘info’ or ‘version’?

Thanks in advance for any suggestions

Like it’s said in the error message; Navigation targets must have unique routes. One view can only have one Route. (You can add more aliases with @RouteAlias, but this is not made for showing different content within the same View, but just a second route name to land on the same View. You could cover different writings of a word like this, i.e. adding an alias “colour” to a “color” route).
I believe it would be theoretically possible then to add different content depending on the current url, but I don’t see why one would prefer this over having separate View classes for each of those Views. It makes it much simpler.

Here is how you do it with separate views:

@Route(value = "main", layout = MainLayout.class)
public class MainView extends VerticalLayout {
	...
}

@Route(value = "info", layout = MainLayout.class)
public class InfoView extends VerticalLayout {
	...
}

@Route(value = "version", layout = MainLayout.class)
public class VersionView extends VerticalLayout {
	...
}

public class MainLayout extends AppLayout implements RouterLayout

  public MainLayout()
  {
    ...
    addToDrawer( createMenuLink( MainView.class, "Main", VaadinIcon.ALARM.create() ) );
    addToDrawer( createMenuLink( InfoView.class, "Info", VaadinIcon.INFO.create() ) );
    addToDrawer( createMenuLink( VersionView.class, "Version", VaadinIcon.QUESTION.create() ) );
  }
  
  private RouterLink createMenuLink( Class<? extends Component> viewClass, String caption, Icon icon )
  {
    final RouterLink routerLink = new RouterLink( null, viewClass );
    routerLink.setClassName( "menu-link" );
    routerLink.add( icon );
    routerLink.add( new Span( caption ) );
    icon.setSize( "24px" );
    return routerLink;
  }  
}

Hi Kasper,

Actually, I cannot predict which routes we need.

We have got an accounting application. Every journal have got its own route. I need a journal (route) for every bank account. This can be one bank account, but it can be multiple bank accounts too. So the route must be dynamically added and it must view the same class.

Is this possible?

Olaf van der Meer:
Every journal have got its own route.

That is not correct. It only needs one route. But that route needs a [parameter]
(https://vaadin.com/docs/v14/flow/routing/tutorial-router-url-parameters.html) that identifies the bank that you want the journal from. The view will always be the same, no matter which bank’s journal you want to display. You just load a different journal from the db, depending on the given bank identifier (usually id) that was passed as parameter.

let’s call that View JournalView. Every time you want to show the journal of a specific bank, you pass the bank’s id as parameter. The View itself always stays the same, but it will load different data from the DB depending on the given parameter.

public class JournalView extends VerticalLayout implements HasUrlParameter<Integer> {

	public JournalView() {
		// prepare whole view:
		//  - add layouts
		//  - add Input Fields and bind them to a Binder<Journal>
	}

	public void setParameter(BeforeEvent event, Integer bankId){
		// load journal from bank with id: bankId
		// use that journal for the Binder in this view, which fills values of that journal in the prepared input fields
	}

}

If you need to pass multiple banks, you could make the type of the parameter to String and concatenate the different bank id’s into a single string. in the setParameter method you then split the string again to get all bank ids.

Thanks. I have got it working.
In my main I use the JournalView as follows:

public class MainLayout extends AppLayout implements RouterLayout
{
  public MainLayout()
  {
    ...
    addToDrawer( createJournalLink( "Bank 1", 1 ) );
    addToDrawer( createJournalLink( "Bank 2", 2 ) );
  }
  
  private RouterLink createJournalLink( String caption, Integer journalId )
  {
    final RouterLink routerLink = new RouterLink( null, JournalView.class, journalId );
    routerLink.setClassName( "menu-link" );
    Icon icon = VaadinIcon.BOOK.create();
    routerLink.add( icon );
    routerLink.add( new Span( caption ) );
    icon.setSize( "24px" );
    return routerLink;
  }
  
}