Stop propagation of ClickEvent

Hello,

I recently switched from plain GWT to Vaadin. I try to migrate our old GWT app to Vaadin; one part consists of a control comprising several nested panels that can be selected with a mouse click. Now my problem is, that all panels have their own MouseListener and as a consequence the mouse listener of every panel under the mouse cursor receives a ClickEvent in case of . However, I only want the topmost panel to process the clickEvent, i.e., I want to stop the event from bubbling up. GWT-ClickEvents provided the event.stopPropagation()-method to do this. I have not yet found out how an event can be canceled in Vaadin but I’m sure there is a simple way to do this. So is there an equivalent to the stopPropagation-method in GWT? Thanks in advance for your help.

Hi,

Events do not propagate or bubble at all in Vaadin like they do in DOM/JavaScript. Vaadin is more like Swing (and many other desktop UI frameworks) in this regard.

It’s hard to give any more advice with this little information about what you are trying to achieve and what your code looks like now; you might want to attach listeners only to your topmost panel, or explicitly pass events to the parent panel.

Best Regards,
Marc

Hi,

thanks for your answer, however, it did not entirely solve my problem. I’ll explain in more detail what I’m about to implement. We’re working on a GUI that allows a user to buid rules starting from a basic if-condition. This condition can then be further customized by adding sub-conditions or exceptions as well as actions to be taken when the conditions are fulfilled (i.e. a then-clause). To do this, the user selects a panel to which he wants to add a condition and then clicks an “Add Condition” button to insert a sub-panel representing the condition (or action). The following image illustrates the GUI.

In the old GWT GUI, each panel had a clickHandler and in the according onClick-method, the clickEvent was canceled in order to stop underlying panels from receiving the clickEvent (e.g. the user clicks Panel 1.1.1 in the image below and does not want Panel 1.1. and Panel 1 to receive click events).

So now I tried to use only one LayoutClickListener on the topmost panel in hierarchy (i.e. Panel 1), as you suggested. However, the clickedComponent of the clickEvent returns whatever component was clicked (Label, VerticalLayout, etc.) and not necessarily the Panel. Of course, a more sophisticated logic might find out the panel the clicked component belongs to but this seems rather cumbersome. In GWT, the stopPropagation-method did what I needed, AFAIK, event.consume() allows the same in Java/AWT. Since I need the Panel that was clicked, I’d prefer an approach as we implemented in GWT, where a clickHandler is registered on every panel and hence the event.getComponent() returns the panel on which the click occured. So is there any way to achieve this with Vaadin? Or should I try an entierly different approach (i.e. some centralized click handling). Currently, my main problem is, that when the user selects Panel 1.1.1, also Panel 1.1. an Panel 1 receive clickEvents (in case of one clickListener per panel).

Please find the code snippet of our panel below.


@SuppressWarnings("serial")
public class ComponentControl extends Panel {

	private final VerticalLayout   mainLayout;
	private final HorizontalLayout labelsLayout;
	private final HorizontalLayout subComponentsLayout;
	   
	
	public ComponentControl() {
		this.mainLayout          = new VerticalLayout();
		this.labelsLayout        = new HorizontalLayout();
		this.subComponentsLayout = new HorizontalLayout();

		this.mainLayout.setSizeFull();
		this.mainLayout.addComponent(this.labelsLayout);
		this.mainLayout.addComponent(this.subComponentsLayout);		
		
		this.addComponent(this.mainLayout);
	}
	
	public void addLabelComponent(AbstractComponent labelComponent) {
		this.labelsLayout.addComponent(labelComponent);
	}
	
	public void addLabelComponents(List<AbstractComponent> labelComponents) {
		for (AbstractComponent labelComponent : labelComponents) {
			this.addLabelComponent(labelComponent);
		}
	}	
	
	public void addSubComponent(AbstractComponent subComponent) {
		this.subComponentsLayout.addComponent(subComponent);
	}
}

I think this is what I’d recommend - a helper method that traverses getParent() upwards until it finds the Panel.

// Marc

Alright, thanks.

For folks looking for a second opinion on the advice to do what seems cumbersome, I’ll pitch in by saying yes, cumbersome is the way to do it in this case. This manual upward traversal is the same thing you would do in Swing if you wanted to delegate the handling of an event to a parent and simulate the bubbling phenomenon.

Note in Swing, event.consume() just stops the component from executing other registered event handlers. It doesn’t stop bubbling, because there’s no bubbling to start with. Bubbling has to be simulated with the dispatchEvent method.