Click Listener on components

In Flow, how can I add a server-side Click Listener to any of the components (for example, a Label or TextField)?

If there isn’t a ready click listener in the component, you’ll need to use the Element API: https://vaadin.com/docs/v10/flow/element-api/tutorial-event-listener.html

-Olli

Thank you Olli for that pointer. I had read that before but forgot about it. With that info, I could implement what I wanted with hardly a couple lines of code!

Awesome!

-Olli

Hi Syam,
would you mind sharing that code, please?

Thanks

Have a look at these:
[Clickable]
(https://github.com/syampillai/SOComponents/blob/master/src/main/java/com/storedobject/vaadin/Clickable.java)
and
[Element Click]
(https://github.com/syampillai/SOComponents/blob/master/src/main/java/com/storedobject/vaadin/util/ElementClick.java)

With this, you can do something like:

Component anyComponent = new ...;
Clickable c = new Clickable(anyComponent);
add(c);
c.addClickListner(...);

Any subtype of ClickNotifier<T extends Component> has the addClickListener method. And any Component has the addListener method where you can pass your eventType class which describes the DOM event you want to listen to.

Hi Syam & Thomas,
thanks for your quick answers.

I am using Vaadin 13 and cannot see the reference to “Clickable”, so I cannot use Syam’s nice code.

I have tried Thomas alternatives and it works in Vaadin 13.

Option 1:

public class TextFieldXimo extends TextField implements ClickNotifier<TextField>{
// Properties, methods and constructor stuff
}

Option 2

public class TextFieldXimo2 extends TextField {
    // To add a clicklistener
	public Registration addClickListener(
		ComponentEventListener<ClickEvent> listener) {
	    	return this.addListener(ClickEvent.class, listener);
	}
	// Properties, methods and constructor stuff
}	

In this option the compiler complaints about raw types, so alternatively I have created another class to avoid this problems

Option 3

public class TextFieldXimo3 extends TextField {
    // To add a clicklistener
	public Registration addClickListener(
		ComponentEventListener<ClickEventXimo> listener) {
	    	return this.addListener(ClickEventXimo.class, listener);
	}
	// Properties, methods and constructor stuff
}	

// And the new class ...

public class ClickEventXimo extends ClickEvent<TextField> {
	public ClickEventXimo(TextField source, boolean fromClient) {
		super(source);
	}
}

I am not good at Vaadin, I think it is a complex but very interesting framework.

Thanks you very much for the help

Ximo Dante:
Hi Syam & Thomas,
thanks for your quick answers.

I am using Vaadin 13 and cannot see the reference to “Clickable”, so I cannot use Syam’s nice code.

I have tried Thomas alternatives and it works in Vaadin 13.

Option 1:

public class TextFieldXimo extends TextField implements ClickNotifier<TextField>{
// Properties, methods and constructor stuff
}

Option 2

public class TextFieldXimo2 extends TextField {
    // To add a clicklistener
	public Registration addClickListener(
		ComponentEventListener<ClickEvent> listener) {
	    	return this.addListener(ClickEvent.class, listener);
	}
	// Properties, methods and constructor stuff
}	

In this option the compiler complaints about raw types, so alternatively I have created another class to avoid this problems

Option 3

public class TextFieldXimo3 extends TextField {
    // To add a clicklistener
	public Registration addClickListener(
		ComponentEventListener<ClickEventXimo> listener) {
	    	return this.addListener(ClickEventXimo.class, listener);
	}
	// Properties, methods and constructor stuff
}	

// And the new class ...

public class ClickEventXimo extends ClickEvent<TextField> {
	public ClickEventXimo(TextField source, boolean fromClient) {
		super(source);
	}
}

I am not good at Vaadin, I think it is a complex but very interesting framework.

Thanks you very much for the help

Hey Ximo,

Sorry for the delayed reply, I think I missed the forum notification. To me “Option 1” looks the most suitable. You can just leave the class definition empty and you can already simply invoke ximoTf.addClickListener(...). The default methods in the ClickNotifier will do the necessary job.

Thanks Thomas!

Syam had a nice idea as you can implement any component with it, or in my case, make compound clickable components, so I made similar implementation of it with Div:

package fi.protieto.sfi.ui.views.components;

import com.vaadin.flow.component.ClickNotifier;
import com.vaadin.flow.component.html.Div;

public class Clickable extends Div implements ClickNotifier<Div> {
}

Now you can use it like:

Clickable c = new Clickable();
c.add(new Label("clickable label"););
c.addClickListener(e -> {
	// do something
});

add(c);

I have in HybridMenu HMdemo, a Label to place the logo, but then I have no possibility to implement a Clickable since there is no method in HMLabel to implement it, and I converted it to button, but then the image loads too big

The code there in that left menu is :

leftMenu.add(HMButton.get()
// .withIcon(VaadinIcon.MENU)
.withCaption(“Menu”)
.withImage(new Image(“./frontend/HybridMenu/Images/Logo.png”, " "))
.withClickListener(e → getLeftMenu().toggleSize()));

WOuld you be so nice to provide a suggestion as to implement this to work

Hi,

You can add a click listener on any Vaadin component using this:
ComponentUtil.addListener(component, ClickEvent.class, listener);

This is how it’s done in the ClickNotifier.

Does it help you?

Jean-Christophe, I appreciate your kindness in supplying me with the above suggestion. Unfortunately it does not work for me in that simple form. Would you be so nice to expand the example so I could apply it to add the clickable possibility to this HMLabel in HybridMenu. ?

I modified the method in Router Layout

leftMenu.add(HMLabel.get()
		.withCaption("Menu")
		.withClickListener(e -> getLeftMenu().toggleSize())
		.withIcon(new Image("./frontend/HybridMenu/Images/Logo.png", " ")));

In Class HMLabel I modified following methods

public HMLabel(String caption, Icon icon, ComponentEventListener<ClickEvent<Label>> clickListener) {
		build(caption, icon, clickListener);
}	
	private void build(String caption, Icon icon, ComponentEventListener<ClickEvent<Label>> clickListener) {
		withCaption(caption);
		withIcon(icon);
		if (clickListener != null) {
			withClickListener(clickListener);
		}
	}

public HMLabel withClickListener(ComponentEventListener<ClickEvent<Label>> clickListener) {
		addClickListener(clickListener);
		return this;
	}

private HMLabel addClickListener(ComponentEventListener<ClickEvent<Label>> clickListener) {
	addClickListener(clickListener);
		return this;
}

StackOverflow error because is recurrent calling itself

I have not been able to find another method to
avoid this stackoverflow error

Only way to work is removing addClickListener(clickListener)
but then the click link is eliminated

Please try to help

Looks like your addClickListener method is calling itself:

private HMLabel addClickListener(ComponentEventListener<ClickEvent<Label>> clickListener) {
	addClickListener(clickListener); // <- recursive call
		return this;
}

I think it could be like this:

leftMenu.add(HMLabel.get()
		.withCaption("Menu")
		.withClickListener(e -> getLeftMenu().toggleSize())
		.withIcon(new Image("./frontend/HybridMenu/Images/Logo.png", " ")));

HMLabel label = HMLabel.get()
		.withCaption("Menu")
		.withIcon(new Image("./frontend/HybridMenu/Images/Logo.png", " "));

ComponentUtil.addListener(label, ClickEvent.class, e -> getLeftMenu().toggleSize());

leftMenu.add(label);

Tommi,

I appreciate your help and the suggestion was really perfect and resolved my situation with this Hybrid Menu left menu label.

I wish you the best

The only issue left is that the hand indicating a link is there is not showing up. Could you suggest anything please