28

I would like to update a text field instantly when typing in a GWT TextBox. My problem is that ValueChangeEvent and ChangeEvent handlers only fire when the TextBox loses focus. I thought about using the KeyPressEvent but then nothing would happen when performing a copy paste with the mouse.

What's the simplest way to do that ?

Jla
  • 11,304
  • 14
  • 61
  • 84

6 Answers6

37

You could catch the ONPASTE event and manually fire a ValueChangeEvent. Something like this:

public void onModuleLoad() {
    final Label text = new Label();
    final ExtendedTextBox box = new ExtendedTextBox();
    box.addValueChangeHandler(new ValueChangeHandler<String>() {

        @Override
        public void onValueChange(ValueChangeEvent<String> event) {
            text.setText(event.getValue());
        }

    });
    box.addKeyUpHandler(new KeyUpHandler() {

        @Override
        public void onKeyUp(KeyUpEvent event) {
            text.setText(box.getText());
        }
    });

    RootPanel.get().add(box);
    RootPanel.get().add(text);
}

private class ExtendedTextBox extends TextBox {

    public ExtendedTextBox() {
        super();
        sinkEvents(Event.ONPASTE);
    }

    @Override
    public void onBrowserEvent(Event event) {
        super.onBrowserEvent(event);
        switch (DOM.eventGetType(event)) {
            case Event.ONPASTE:
                Scheduler.get().scheduleDeferred(new ScheduledCommand() {

                    @Override
                    public void execute() {
                        ValueChangeEvent.fire(ExtendedTextBox.this, getText());
                    }

                });
                break;
        }
    }
}

Tested on firefox 3.6.1.

z00bs
  • 7,518
  • 4
  • 34
  • 53
  • 1
    Thanks. This worked for me. One thing for others to note is that the deferred command is required because the TextBox does not yet contain the text of interest when the paste event is handled. If you are trying to filter the contents of the text box (in my case, for valid characters), note that a user will momentarily see the pasted text. Anyone know any ways around this? From what I've read, FF does not allow clipboard inspection, but both IE and Webkit do? – ShabbyDoo Nov 04 '10 at 19:59
  • What you could do is to hide the content of the `TextBox` until validation is done. It's really a hack but `color: transparent` would do the trick... – z00bs Nov 08 '10 at 12:05
  • @z00bs Is this possible to do without extending TextArea and using UiBinder? – alexandroid Nov 08 '11 at 02:30
  • I doubt it since you somehow need to extend the behavior in `onBrowserEvent()`. – z00bs Nov 08 '11 at 07:23
  • 2
    Great answer, but in recent versions of GWT, DeferredCommand has been deprecated in favour of Scheduler.get().scheduleDeferred(...) – Renato Feb 19 '12 at 23:23
  • Instead of extending TextBox you could simply use JSNI like here: http://stackoverflow.com/a/4018317/193016 – kroiz Jul 22 '12 at 12:19
5

As a general solution, what works for me (thx to gal-bracha comment):

Generally, GWT does not have classes to handle input event (described here and here). So we need to implement it by ourselves:

Handler class:

import com.google.gwt.event.shared.EventHandler;

public interface InputHandler extends EventHandler {

  void onInput(InputEvent event);

}

Event class:

import com.google.gwt.event.dom.client.DomEvent;

public class InputEvent extends DomEvent<InputHandler> {

    private static final Type<InputHandler> TYPE = new Type<InputHandler>("input", new InputEvent());

    public static Type<InputHandler> getType() {
        return TYPE;
    }

    protected InputEvent() {
    }

    @Override
    public final Type<InputHandler> getAssociatedType() {
        return TYPE;
    }

    @Override
    protected void dispatch(InputHandler handler) {
        handler.onInput(this);
    }

}

Usage:

box.addDomHandler(new InputHandler() {

    @Override
    public void onInput(InputEvent event) {
        text.setText(box.getText());
    }
},InputEvent.getType());

It works on every TextBox value change including pasting using context menu. It does not react on arrows, ctrl, shift etc...

zolv
  • 1,720
  • 2
  • 19
  • 36
2

This has been a major issue for me in the past. The keyupHandler wont work because the copy paste requires a second key press on the paste option which does not fire the event. the best i have been able to do is use the old changelistener not ideal but it does work.

  • 1
    Better to use the input event, But I'm not sure how to access it from gwt. It handles both paste, and keyboard, as it raises when the value actually changes. https://developer.mozilla.org/en/DOM/DOM_event_reference/input – Gal Bracha Feb 28 '12 at 13:54
2

I prefer use Elements than Widgets so this my way to handler.

    Element input = Document.get().getElementById("my-input");
    DOM.sinkBitlessEvent(input, "input");
    DOM.setEventListener(input, event -> GWT.log("Event!"));
Daniel De León
  • 13,196
  • 5
  • 87
  • 72
1

Why not use combination of both KeyUpHandler and a ChangeHandler on the TextBox? Should take care of immediate feedback on each keystroke as well as copy paste case as well.

Ashwin Prabhu
  • 9,285
  • 5
  • 49
  • 82
  • As I said the ChangeHandler only fires once the TextBox loses focus but I would like to update my field instantly (while the user is typing). – Jla Jul 06 '10 at 11:54
  • Hmmm... Did you figure out a way? Please shares the solution when you do :) Thanks – Ashwin Prabhu Jul 08 '10 at 08:48
  • The behaviour change on lose of focus was accepted after all for the app I was working on. So I never did find a solution and left it aside for the moment. But will update the question if ever I find one. – Jla Jul 16 '10 at 08:32
  • Best thing is to use the input event, But I'm not sure how to access it from gwt. It handles both paste, and keyboard, as it raises when the value actually changes. https://developer.mozilla.org/en/DOM/DOM_event_reference/input – Gal Bracha Feb 28 '12 at 13:53
0
Just saw this question. Because I was facing the similar problem. 

Did some hack and it worked for me. You can use KeyUpHandler but use it with additional if block that checks for length of textbox. If length of text box is > 0, do your thing. Ex:

textBox.addKeyUpHandler(new KeyUpHandler() {
    @Override
    public void onKeyUp(KeyUpEvent keyUpEvent) {
    if (textBox.getText().length() > 0) {
    //do your stuff`enter code here`

    }
    }
Bikas Katwal
  • 1,895
  • 1
  • 21
  • 42
  • This does not account for dragging values into the box, also triggers on left/right keyrelease, ctrl keyrelease – WORMSS Sep 22 '16 at 09:44
  • true, this will be applicable for typing which includes text. I guess that will serve purpose for this question. Its just a hack ;) – Bikas Katwal Oct 25 '16 at 07:37