Duplication of PopOver

Hi,

I encountered some kind of strange behaviour with the new component PopOver. It gets like duplicated on some conditions I could not determine.

Description of the system surrounding the component:

I have a view with an TreeGrid as a navigation component. When I select items on there, most of the components gets switched out for the components of the selection. One of the components, that (mostly) stay, is an Icon with a PopOver. The PopOver holds a description of the other components of the view at the time. To do that the text in the PopOver gets changed, when a new item is selected in the TreeGrid.

Description of the PopOver initialisation:

The PopOver and the icon are components of the same java file. I initialise it with the VaadinIcon which should hold the PopOver. The PopOver contains a VerticalLayout to get padding etc. I set it to open on hover, give it a delay time for the hover to activate, define, that it should close on outside click and set the target to my icon component.

In the VerticalLayout is a span which holds the text I want to display. The text gets changed over a public method. Also, the text in HTML, so I set it with “this.text.getElement().setProperty(’innerHTML’, content);”.

Description of the problem:

When I open the view an select an item from the TreeGrid all components are displayed correctly. But when I hove above the icon two PopOvers open. One is the correct one with the desired text. One is completely empty.

Results of testing:

The empty PopOver is the version, before the text was set. So, if set text to my span in the initialisation this text is display in the PopOver.

My constructor is only called once in the whole application, so there is no way I could have added another PopOver to the icon. The only method which is called multiple times is the one to set the text of the span.

I found a workaround: When I set the target not at initialisation, but when the texts get exchanged, the empty PopOver does not show up.

I saw, that there was an Issue (now closed) for a race condition to the PopOver, but the use of the lasts version of Vaadin (24.5.7) did not resolve the problem.

I have other views with PopOvers that have changing content, that doesn’t have this kind of problem.

When I don’t set text to the span after the initialisation, it only shows one PopOver. I also tried to comment out all lines, that were not needed, but the problem persisted.

My guess is that it has something to do with the attachment and detachment of the icon, because if no TreeGrid item is selected, only the TreeGrid is shown. But is only a guess and I could not prove it.

Any chance you could share some code?

Also, did you try not setting the the text through getElement? (I don’t think it should be a problem, but it is a low-level API to the html element which might not work well with the way elements are moved into the overlay…

Hi,
I can share the class that I use to initialise the PopOver and the methods I call on it.
This ist the class:

public class ExtendedTooltipText
    extends Span {

  private static final int HOVER_DELAY = 1500;
  private static final String STYLE_POPUP = "extendedtooltip-popup"; //$NON-NLS-1$

  private VerticalLayout fContent = new VerticalLayout();
  private Span text = new Span();
  private final Popover popOver;

  private final Component fHeaderComponent;

  public ExtendedTooltipText(VaadinIcon icon) {
    this(icon.create());
  }

  private ExtendedTooltipText(Component header) {
    this.fHeaderComponent = header;
    addClassName(STYLE_POPUP);
    add(this.fHeaderComponent);

    this.popOver = new Popover();
    this.popOver.setTarget(this);
    this.popOver.setOpenOnHover(true);
    this.popOver.setHoverDelay(HOVER_DELAY);
    this.popOver.setCloseOnOutsideClick(true);

    this.fContent.setSpacing(false);
    this.fContent.setMargin(false);
    this.fContent.setPadding(true);
    this.fContent.setWidth(700, Unit.PIXELS);
    this.popOver.add(this.fContent);
    this.fContent.add(this.text);

    this.text.getElement().getStyle().setWhiteSpace(Style.WhiteSpace.PRE_WRAP);
    this.text.getElement().getStyle().set("Word-Wrap", "break-word"); //$NON-NLS-1$ //$NON-NLS-2$
  }

  public void addClassNameHeader(String classname) {
    this.fHeaderComponent.addClassName(classname);
  }

  public void setContent(String content) {
    this.text.removeAll();
    if (content != null) {
      this.text.getElement().setProperty("innerHTML", content); //$NON-NLS-1$
    }
  }

  public void setSize(String size) {
    if (this.fHeaderComponent instanceof Icon) {
      if (size != null) {
        ((Icon) this.fHeaderComponent).setSize(size);
      }
    }
  }

  public enum VerticalAlignmentPopup {
    Top, Bottom, Middle
  }

  public void setVerticalAlignment(VerticalAlignmentPopup alignment) {
    switch (alignment) {
    case Bottom:
      this.fHeaderComponent.getElement().getStyle().set("vertical-align", "bottom"); //$NON-NLS-1$ //$NON-NLS-2$
      break;
    case Middle:
      this.fHeaderComponent.getElement().getStyle().set("vertical-align", "middle"); //$NON-NLS-1$ //$NON-NLS-2$
      break;
    case Top:
      this.fHeaderComponent.getElement().getStyle().set("vertical-align", "top"); //$NON-NLS-1$ //$NON-NLS-2$
      break;
    default:
      break;
    }
  }
}

and like this I initialise my ExtendedTooltipText in the class I use it:

this.fIcoInfoText = new ExtendedTooltipText(VaadinIcon.INFO_CIRCLE_O);
    this.fIcoInfoText.addClassName([Style_for_Span_Surrounding_Other_Components]);
    this.fIcoInfoText.setSize("18px"); //$NON-NLS-1$
    this.fIcoInfoText.getStyle().setMarginLeft("6px"); //$NON-NLS-1$
    this.fIcoInfoText.getStyle().setMarginRight("6px"); //$NON-NLS-1$
    this.fIcoInfoText.setVerticalAlignment(VerticalAlignmentPopup.Top);

When a new Item for my TreeGrid is seleted, it is determined, if the ExtendedTooltipText is visible and the new text is set with setContent(). To mention: when the view is initial shown, the Component is not visible.
I tried to set text in the method with setText() at the span (ignoring the looks for the moment) but it did not change the behaviour of the PopOver.

I tried to use your above code example and it’s was unable to reproduce the issue.
If possible, please share a minimal project where this issue can be reproduced.

Hi,
I have finally got my minimal example to show the (for me) unexpected behaviour. Take the ExtendedTooltipText class as I postet before and this view:

@Route(value = "popoverTest")
public class TestTooltipView
    extends VerticalLayout {

  private ExtendedTooltipText tooltip = new ExtendedTooltipText(VaadinIcon.PLAY_CIRCLE_O);

  public TestTooltipView() {
    VerticalLayout vl = new VerticalLayout();
    vl.setSizeFull();
    vl.setMargin(false);
    vl.setPadding(false);
    vl.setSpacing(false);

    this.tooltip.setVisible(false);
    HorizontalLayout hlTooltip = new HorizontalLayout(this.tooltip);

    Button btnTriggerTooltipIcon = new Button("Change visibility Icon");
    btnTriggerTooltipIcon.addClickListener(e -> {
      if (this.tooltip.isVisible()) {
        this.tooltip.setVisible(false);
        hlTooltip.removeAll();
      } else {
        this.tooltip.setVisible(true);
        this.tooltip.setContent("New Text");
        hlTooltip.setVisible(true);
        hlTooltip.add(this.tooltip);
      }
    });

    vl.add(btnTriggerTooltipIcon);
    vl.add(hlTooltip);
    this.add(vl);
  }
}

When you open the view, click on the button to change the visibility of the icon and then hover over the icon. In the HTML you can see, that two PopOvers were added and on the view theres one PopOver with Text and an white bar on top of it.

Thank you, now I’m able to reproduce the problem. Reported an issue with a simplified example [popover] Adding target twice causes two popover overlays to be opened · Issue #6953 · vaadin/flow-components · GitHub. This is likely the problem with auto-adding logic of Popover. I’ll investigate how to fix this.

2 Likes