Which event should I use, to check if view was loaded into component? / Log

I created a RapidClipseX java application.

The MainContainer, has a horizontal Menue and a ContentContainer included.

RapidClipseX includes Vaadin14.

After start of the application the loginView opens inside the ContentContainer.
After successful login, the MainView (Home) was loaded into the ContentContainer.
So far so fine. Please see also attached screenshot

Currently the Menue.visible = false.

After login I would like to change the visibility of the menue to true.

My idea was, to validate, out of MainContainer, if ContentContainer has the LoginView, or the MainView loaded.

If MainView was loaded, I would like to switch visibility of menue to true.

In Vaadin8 was a event like ContentContainer.componentAttach which I could use to change visibility of Menue to true.

How to do this in Vaadin14?

Any help/hint would be fine!

Thank you in advance!

My mainContainer.java:

package com.rieder.finmgmt.ui;

import com.rapidclipse.framework.server.security.authorization.Authorization;
import com.rapidclipse.framework.server.security.authorization.SubjectEvaluatingComponentExtension;
import com.rapidclipse.framework.server.security.authorization.SubjectEvaluationStrategy;
import com.rieder.finmgmt.AuthorizationResources;
import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.ComponentEvent;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.HasElement;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.contextmenu.MenuItem;
import com.vaadin.flow.component.contextmenu.SubMenu;
import com.vaadin.flow.component.dependency.HtmlImport;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.menubar.MenuBar;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.FlexLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.RouterLayout;
import com.vaadin.flow.server.InitialPageSettings;
import com.vaadin.flow.server.PageConfigurator;
import com.vaadin.flow.theme.Theme;
import com.vaadin.flow.theme.lumo.Lumo;

import lombok.extern.slf4j.Slf4j;


/**
 *
 */
@Slf4j
@HtmlImport("frontend://styles/shared-styles.html")
@HtmlImport("frontend://styles/my-menubar.html")
@Route(value = "MainLayout", registerAtStartup = false)
@Theme(value = Lumo.class, variant = Lumo.LIGHT)
public class MainContainer extends VerticalLayout implements PageConfigurator, RouterLayout
{
	/**
	 *
	 */
	public MainContainer()
	{
		super();
		this.initUI();

		
		final MenuItem itemHome = this.navMenuBar.addItem("home");
		itemHome.addClickListener(e -> UI.getCurrent().navigate(MainView.class));

		final MenuItem itemCat1    = this.navMenuBar.addItem("Dokumenten Management");
		final SubMenu  subMenuCat1 = itemCat1.getSubMenu();

		final MenuItem itemView11 = subMenuCat1.addItem("edit Inhaltsverzeichnis Schränke");
		itemView11.addClickListener(e -> UI.getCurrent().navigate(EditInhSchraenke.class));

		final MenuItem itemView12 = subMenuCat1.addItem("edit Schränke");
		itemView12.addClickListener(e -> UI.getCurrent().navigate(EditSchraenke.class));

		final MenuItem itemView13 = subMenuCat1.addItem("edit Lieferanten");
		itemView13.addClickListener(e -> UI.getCurrent().navigate(EditLieferanten.class));

		final MenuItem itemCat2    = this.navMenuBar.addItem("Finanzmanagement");
		final SubMenu  subMenuCat2 = itemCat2.getSubMenu();
        ......a.s.o
		
	}

	@Override
	public void configurePage(final InitialPageSettings settings)
	{
		settings.addLink("shortcut icon", "frontend/images/favicon.ico");
		settings.addFavIcon("icon", "frontend/images/favicon256.png", "256x256");
	}

	@Override
	public void showRouterLayoutContent(final HasElement content)
	{
		
		this.contentContainer.removeAll();
		this.contentContainer.getElement().appendChild(content.getElement());

	}

	/**
	 * Event handler delegate method for the {@link FlexLayout} {@link #contentContainer}.
	 *
	 * @see ComponentEventListener#onComponentEvent(ComponentEvent)
	 * @eventHandlerDelegate Do NOT delete, used by UI designer!
	 */
	private void contentContainer_onAttach(final AttachEvent event)
	{
		// something to do
	}

	/* WARNING: Do NOT edit!<br>The content of this method is always regenerated by the UI designer. */
	// <generated-code name="initUI">
	private void initUI()
	{
		this.headContainer    = new HorizontalLayout();
		this.lblHead          = new Label();
		this.navMenuBar       = new MenuBar();
		this.contentContainer = new FlexLayout();

		this.setSpacing(false);
		this.setPadding(false);
		this.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.STRETCH);
		this.headContainer.setClassName("my-header");
		this.headContainer.setSpacing(false);
		this.headContainer.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.CENTER);
		this.lblHead.setText("Rieder's Finanzmanagement");
		this.navMenuBar.setClassName("my-menubar");
		this.contentContainer.setMinHeight("0");

		Authorization.setSubjectEvaluatingComponentExtension(this.navMenuBar, SubjectEvaluatingComponentExtension.Builder
			.New().add(AuthorizationResources.AFTERLOGIN.resource(), SubjectEvaluationStrategy.VISIBLE).build());

		this.lblHead.setSizeUndefined();
		this.headContainer.add(this.lblHead);
		this.headContainer.setSizeUndefined();
		this.navMenuBar.setWidth(null);
		this.navMenuBar.setHeight("35px");
		this.contentContainer.setSizeUndefined();
		this.add(this.headContainer, this.navMenuBar, this.contentContainer);
		this.setFlexGrow(1.0, this.contentContainer);
		this.setSizeFull();

		Authorization.evaluateComponents(this);

		this.contentContainer.addAttachListener(this::contentContainer_onAttach);
	} // </generated-code>

	// <generated-code name="variables">
	private MenuBar          navMenuBar;
	private FlexLayout       contentContainer;
	private HorizontalLayout headContainer;
	private Label            lblHead;
	// </generated-code>

}

Hi Heinz,

Use onAttach. It will do it for you.

https://vaadin.com/docs/flow/creating-components/tutorial-component-lifecycle-callbacks.html

Also take a look at the life cycle:

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

I am sorry, but I didn’t got it.

I could not transfer the content out of the provided links to my requirement.

The component which I have to change is a component inside MainContainer (It is the MenueBar)

The component which I have to check for an update is the ContentContainer also inside MainContainer.

I have to validate if the LoginView is detached (means Login successful) and the HomeView is attached to the ContentContainer.

If yes, I can set visibility of the MenuBar to true

If Login is not successful the MenuBar should not be visible

The onAttach Method can I use only on deeper level - on my HomeView → or am I wrong?

If I am right, how can I change out of my HomeView - onAttach-Event → a deeper level

in the component hierarchy, a behavior of a component which is attached a level higher?

Sorry, but as I told there is not so much experience.

Thank you in advance for any help!

Hi Heinz,

It would be a much longer conversation, but in short, you should not use the detachment of the loginview to assume that the user authenticated. It is bad design for several reasons;

  • If something else removed the LoginView or an error occured and the LoginView detached, your application would see that as a successfull login.
  • It creates a tight coupling between the LoginView and the MainView. If you later change your LoginView, the MainView may stop working correctly.

What you should do, is to prevent users from navigating to the main view and all other views unless the user has authenticated. That’s alot of work, but you can find some examples here:

  • The bakery app starter
  • The business app starter

This article: https://vaadin.com/learn/tutorials/securing-your-app-with-spring-security/setting-up-spring-security