0

I try to code a TexField that fire an event (a search) on every key press.

But the event should have a debounce option so that it triggers only after a given time without pressing a key.

I follow this documention: https://vaadin.com/docs/v13/flow/creating-components/tutorial-component-events.html

But I struggle to understand how to add the @DebouceEvent to my TextField...

The event:

@DomEvent(value = "input",
          debounce = @DebounceSettings(
              timeout = 250,
              phases = DebouncePhase.TRAILING))
public class InputEvent extends ComponentEvent<TextField> {
    private String value;

    public InputEvent(TextField source, boolean fromClient,
            @EventData("element.value") String value) {
        super(source, fromClient);
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

The TextField:

 TextField searchField= new TextField("my search");

I tried:

searchField.addInputListener(new InputEvent(searchField, true, "input"));

erro:

Error:(41, 38) java: incompatible types: nc.unc.importparcoursup.view.AdmisDetailView.InputEvent cannot be converted to com.vaadin.flow.component.ComponentEventListener<com.vaadin.flow.component.InputEvent>
Tyvain
  • 2,640
  • 6
  • 36
  • 70

2 Answers2

3

There are two problems with this line

searchField.addInputListener(new InputEvent(searchField, true, "input"));
  1. The addInputListener is not for your event, it just happens to be named similarly
  2. The argument should be a listener, not an event

Solution

In order to add your custom event, you need to extend the TextField class (or build your own text field that extends Component).

I call my field SearchField

public class SearchField extends TextField {

    public SearchField(String caption) {
        super(caption);
    }
}

Next, we can create the event class. I changed the name to SearchEvent to avoid confusion. I also made the delay larger so that it would be easier to test if it works. Lastly, here it extends ComponentEvent<TextField>, but it could also extend ComponentEvent<SearchField>.

@DomEvent(value = "input",
        debounce = @DebounceSettings(
                timeout = 1000,
                phases = DebouncePhase.TRAILING))
public class SearchEvent extends ComponentEvent<TextField> {
    private String value;

    public SearchEvent(TextField source, boolean fromClient,
                       @EventData("element.value") String value) {
        super(source, fromClient);
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

Now we can create a method for adding a listener of this event type in the SearchField class.

public class SearchField extends TextField {

    ...

    public Registration addSearchListener(ComponentEventListener<SearchEvent> listener) {
        return addListener(SearchEvent.class, listener);
    }
}

And finally we can try it out

@Route
public class SearchView extends VerticalLayout {

    public SearchView() {
        SearchField searchField = new SearchField("Search");
        searchField.addSearchListener(event -> {
            Notification.show("You searched for [" + event.getValue() + "]");
        });
        add(searchField);
    }
}

Note

In Vaadin 14, which is currently in pre-release and should be released shortly, you can simply do

TextField textField = new TextField();
textField.setValueChangeMode(ValueChangeMode.LAZY);
Erik Lumme
  • 5,202
  • 13
  • 27
2

I think you are adding unnecessary complexity in your approach. TextField has setValueChangeMode and setValueChangeTimeOut methods which can be used to configure the TextField to behave as you are apperently trying to. See https://vaadin.com/api/platform/14.0.0.rc7/com/vaadin/flow/component/textfield/TextField.html#setValueChangeTimeout-int-

Tatu Lund
  • 9,949
  • 1
  • 12
  • 26
  • Please note that `ValueChangeMode.LAZY` and `setValueChangeTimeOut` are new features in Vaadin 14 which is currently only available as a prerelease. With versions 10-13, you'd have to either use the approach described by @Tazavoo or use the generic low-level `addEventListener` method on `searchField.getElement()`. – Leif Åstrand Aug 06 '19 at 06:18