vaadinvaadin-flowvaadin10

Vaadin @DebouceSettings example


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>

Solution

  • 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);