Change NavBar content in AppLayout dynamically when navigation occurs

Hi,

I would like to have a set of buttons in the AppLayou NavBar section that is dependent on the page shown (in the content section). My setup is fairly simple with the a set of RouterLink links in the drawer (wrapped in tabs) and the content set by instanciating a view when the link is clicked.

I would like each view to be able to add a relevent set of buttons to the AppLayout navBar, but I don’t know how to access it. I was hoping the a parent layout would be availble to a child view, or that I could pass the parent layout to the child. However, (I assume) the view does not exist until the RouterLink generates it, so I can’t pass the layout

I also considered firing an event when the router navigates, but I can’t work out how to add a listener in the child view.

Perhaps I’m overthinking it… Is there a straightforward way to do this?

Thanks!

MainLayout.java

public class MainLayout extends AppLayout implements BeforeEnterObserver, TrackerConfigurator {

    private Map<Tab, Component> tabSet = new HashMap<>();
	
	public MainLayout() {
	
			FlexLayout navBarLayout = new FlexLayout(leftNavBarLayout, navBarContentContainer, rightNavBarLayout);
            navBarLayout.setWidthFull();
            navBarLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
            navBarLayout.setAlignItems(FlexComponent.Alignment.CENTER);
            addToNavbar(navBarLayout);
			
			// Tabs
            TabWithIdentifier page0 = tabForPageWithRouter("Dashboard", new IronIcon("icomoon", "icons"), DashboardView.class);
            TabWithIdentifier page1 = tabForPageWithRouter("Users", new IronIcon("icomoon", "users2"), UserView.class);
			...
			
			final Tabs tabs = new Tabs(page0, page1, ...);
            tabs.setOrientation(Tabs.Orientation.VERTICAL);
			
			addToDrawer(tabs);
	}
	
	private TabWithIdentifier tabForPageWithRouter(String title, IronIcon icon, Class classType) {

        icon.setSize("1.3em");
        icon.getStyle().set("margin-right", "10px");

        RouterLink routerLink = new RouterLink(null, classType);
        routerLink.add(icon);
        routerLink.add(title);

        TabWithIdentifier tab = new TabWithIdentifier(routerLink);
        tab.setId(title);
        tab.setIdentifier(title);
        tab.addClassName("drawer-tab");

        return tab;
    }

In the view I would like to access navBarContentContainer, clear out any controls from the last page visited and add buttons relevant for the current view.

Resolved it.

[https://stackoverflow.com/questions/66663019/change-navbar-content-in-applayout-dynamically-when-navigation-occurs/66663752#66663752]

Hi Tino,

It probably depends on whether you want the AppLayout to control what is being shown or if you want to let the actual views control what is being shown.

You solution on SO looks fine if you want the AppLayout to control what is being shown. If you your views to control it, you can use onAttach and onDetach to add and remove buttons etc. from the layout. If you have a few views you can definitely let the layout control it, but if you have lots of views, it will be more manageable to let each view control their own buttons etc.

Here’s an example from a view from my app that attaches it’s own components to the app layout’s left sidebar (my app layout is not the exact same as the Vaadin app layout).


	@Override
	protected void onAttach(AttachEvent attachEvent) {
		super.onAttach(attachEvent);

		// Add calendar filter
		AdminAppLayout aal = AdminAppLayout.getInstance();
		if (aal != null) {
			aal.getLeftSideBar().add(calendarFilter);
			aal.setAddTimeslotVisible(true);
		}

	}

	@Override
	protected void onDetach(DetachEvent detachEvent) {

		// Remove calendar filter
		AdminAppLayout aal = AdminAppLayout.getInstance();
		if (aal != null) {
			aal.getLeftSideBar().remove(calendarFilter);
			aal.setAddTimeslotVisible(false);
		}
		super.onDetach(detachEvent);
	}

and from AppLayout:

	/**
	 * Returns the current active instance
	 * 
	 * @return
	 */
	public static AdminAppLayout getInstance() {
		return (AdminAppLayout) UI.getCurrent().getChildren()
				.filter(component -> component.getClass() == AdminAppLayout.class).findFirst().orElse(null);
	}

Also here’s a link that outlines the lifecycle for a view:

https://vaadin.com/docs/v14/flow/routing/tutorial-routing-lifecycle.html

Thanks Martin. Your solution looks good - I’ll certainly be able to use it!