Access URL Parameter from @Route(layout)

Hi all,

I’m evaluating/prototyping Vaadin for an application and need a bit of help with something.

I have a “MainLayout” which has a menu bar which contains RouterLinks.

Some of the child pages have a URL Parameter.

My question is, how can I access the URL Parameter from the Main Layout?
I want to update some of the RouterLinks in the MainLayout, based on the URL Parameter received by the child component.

Here is a page that uses MainLayout:

@Route(value = "home", layout = MainLayout.class)
public class HomeView extends VerticalLayout implements HasUrlParameter<String>  {

Have you any advice on how to inform the parent layout of the URL parameter(s) ?

You could implement BeforeEnterObserver in your MainLayout. In the beforeEnter method, take a look at the event.getLocation() location.

In your case the following should hold true for the Location:

  • location.getPath() is /home/myparam
  • location.getSegments() is a list of home and myparam
  • location.getSubLocation() is an Optional<Location> containing a location with path myparam and segment myparam

With this in mind you can probably build something that fits your requirements, here’s an example

@Override
public void beforeEnter(BeforeEnterEvent event) {
	event.getLocation().getSubLocation().ifPresent(location -> System.out.println(location.getSegments()));
}

Thanks for the reply Erik, I will try it out, as it is so much simpler than what I came up with last night :slight_smile:

I eventually came up with an odd solution with a new interface, called “ParentNotifier”

interface ParentNotifier {
  <T extends ComponentEvent<?>> Registration addParentListener(
      Class<T> eventType, ComponentEventListener<T> listener);
}

Also in the MainLayout I overrode showRouterLayoutContent, so the Parent Layout can add a listener to the child;

class MainLayout extends Div implements RouterLayout {
      
  @Override
  public void showRouterLayoutContent(HasElement content) {
    RouterLayout.super.showRouterLayoutContent(content);
	
    if (content instanceof ParentNotifier) {
      ((ParentNotifier) content)
          .addParentListener(
              ParameterChangeEvent.class,
              event -> {
                if (!event.getParameterList().equals(this.getParameterList)) {
                  // Do something with the parameters
                }
              });
    }
  }

I also have a ParameterChangeEvent which the ‘child’ can fire from within setParameter

class ParameterChangeEvent extends ComponentEvent<Component> {

  private final List<String> parameterList;

  public ParameterChangeEvent(Component source, List<String> parameterList) {
    super(source, false);
    this.parameterList = Collections.unmodifiableList(parameterList);
  }

  public List<String> getParameterList() {
    return parameterList;
  }
}

Finally the child has,

class ParameterisedVerticalLayout extends VerticalLayout 
    implements HasUrlParameter<String>, ParentNotifier {

  @Override
  public <T extends ComponentEvent<?>> Registration addParentListener(
      Class<T> eventType, ComponentEventListener<T> listener) {
    Registration registration = addListener(eventType, listener);

    // Fire an AppChangeEvent because setParameter is usually called
    // BEFORE addParentListener, so we don't want to miss that event.
    if (eventType.isAssignableFrom(ParameterChangeEvent.class)) {
	  // TODO: not sure if fireEvent(...) would be better but that would notify all listeners
      listener.onComponentEvent((T) new ParameterChangeEvent(this, this.parameterList));
    }
    return registration;
  }
  
  @Override
  public final void setParameter(BeforeEvent event, @WildcardParameter String parameters) {
    // Do some things to process the parameters...
	fireEvent(new ParameterChangeEvent(this, this.parameterList));
  }

It works! But its a lot more code than your solution.

Will try it out.

Thanks - Adam

Having the child somehow notify the parent is a valid solution, hopefully you can get it working with the shorter code as well without it requiring too much code in the MainLayout :slight_smile: