Given the following code:
TextBox tb = new TextBox();
tb.addValueChangeHandler(new ValueChangeHandler<String>() {
#Override
public void onValueChange(ValueChangeEvent<String> event) {
Window.alert(event.getValue());
}
});
onValueChange will be called if the TextBox loses focus. I am trying to have it called whenever the input value changes. The solutions I have read all involve handling the keyup and paste events such as in this answer. How to build a Facebook-style input box in GWT Hasn't this been addresses in GWT 2.5.1? Is there a way to bind to the native input change method? Another widget or using the UI framework would be acceptable if they have this functionality
The only way in GWT is to bind to the key down/key up and paste events.
Please send a patch to add support for the input event (using addBitlessDomHandler): http://www.gwtproject.org/makinggwtbetter.html, it should be rather easy (add a acase in DOMImpl) and has good chances to make it in (and if sent early enough, would have good chances to ship in GWT 2.6)
The solution is use the right event and that is the input event, so look how to hook on it, there are many ways to do it. Because I work with elements and not with Widgets this the code that I use it:
Element input = Document.get().getElementById("my-input");
DOM.sinkBitlessEvent(input, "input");
DOM.setEventListener(input, event -> GWT.log("Event!"));
You can just use addChangeHandler() and onChange, tb.getValue().
I used the following to detect when the value of a textbox changes. Just bare in mind this only detects if the text box goes from empty to full or full to empty. This was done to try reduce async calls to the server to validate the input
#UiHandler("notes")
#SuppressWarnings("unused")
public void notes(KeyUpEvent event) {
if (!areNotesCaptured && !notes.getText().isEmpty()){
fireLeaveSelectionUpdatedEvent();
areNotesCaptured = true;
} else if (areNotesCaptured && notes.getText().isEmpty()){
fireLeaveSelectionUpdatedEvent();
areNotesCaptured = false;
}
}
Related
I've got a GWT 2.4 app where I'm "swapping views" by switching out one Composite widget on the RootPanel for another, using the usual RootPanel.get().clear() and RootPanel.get().add(newWidget) to remove and add, respectively.
The first composite widget contains a PasswordTextBox. It listens for the Enter keypress, which triggers the swap. Nothing too fancy:
getDisplay().getPasswordBoxForKeyPresses().addKeyPressHandler(new KeyPressHandler() {
public void onKeyPress(KeyPressEvent event) {
if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
swapWidgets(); // clear RootPanel and add new widget
}
}
});
The problem is that there is a DOM memory leak: after RootPanel.get().clear() is called, the old composite widget is stuck in the detached DOM tree because the HTMLInputElement for the PasswordTextBox has some strange reference to it which I cannot identify.
Update:
I took the helpful advice below, compiled at style=detailed and started trying to drive down the tree to look a reference to the element in JS. I'm pretty new with GWT, so it still isn't obvious to me what's going on. So starting with the second line in the retaining tree, I can see that lastEvent in _2 contains the nativeKeyTarget listed at the top of tree. But where do I go from there?
I tracked the reference down to SmartGWT. It tracks the last click event within ISC_Core.js. Further questions are
How will this behavior further affect memory usage in my app?
Can this behavior be bypassed if need be?
But those questions are for another post!
Looks like you may not be tracking the handler registrations which will cause memory leaks, prevent objects from being recovered, and cause phantom event captures.
In pure GWT, it looks like this
// class member
HandlerRegistration reg;
// save for recovery
reg = getDisplay().getPasswordBoxForKeyPresses().addKeyPressHandler(...);
public void onDetatch() {
// recover memory
reg.removeHandler();
reg = null;
}
GXT has a nice grouping feature to prevent registration sprawl, it looks like this
// class member
GroupingHandlerRegistration regs = new GroupingHandlerRegistration();
// save for later recovery
regs.add( getDisplay().getPasswordBoxForKeyPresses().addKeyPressHandler(...) );
// recover memory
regs.removeHandler();
Source code for GroupingHandlerRegistration
I have a GXT 3 TextArea on which I catch copy-paste events. On this event, I would like to get the text that is inside the textarea.
Problem : the textarea still has the focus so the value is not updated. Hence, getValue() returns an empty string...
I tried to call getValue() getCurrentValue() flush() validate().
I also tried to extend TextArea to have access to blur() method and call it before getting the value : it makes no difference.
Any solution? (even solution with GWT components would be appreciated).
Without seeing the code you have, it is difficult to say for sure. But at a guess, you are listening to the event, and invoking getCurrentValue() (the correct call in this case) right away.
This is wrong - it is possible for the event handler to call preventDefault(), to cancel the default behavior of that event for most events that can take place. After the event handler returns, only then does the browser actually perform the action (paste or drawing the key that was pressed). The solution to this is to wait a moment before trying to read, to wait until after the action has been completed. The simplest way to achieve this is to schedule a deferred command after the event has occurred, and read the field's value then.
//in the event handler of your choice...
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override
public void execute() {
String pastedValue = field.getCurrentValue();
//do something with the value now
}
});
Before getting the value you can call
yourTextField.finishEditing();
After it method getValue() should return the value of the field. If you would like to keep this field focused after getting the value you can always call
yourTexField.focus();
I use the onStartPage event handler to write a header, works great, but I need to know whether I issued a NewPage() or it was issued due to a page overflow. Is there an elegant way to tell?
Thanks in advance for any help!
You've written a page event implementation, and you've implemented one or more of its methods. You create an instance of this event like this:
MyPageEvent event = new MyPageEvent();
writer.setPageEvent(event);
Whenever the onStartPage() is called, you want to know if it was called from within iText or from your code using the newPage() method. As iText uses the same newPage() method internally, you'll have to use a trick.
Add a memberVariable to your page event application. Something like:
protected boolean myNewPage = false;
Now add this method to your event:
public void newPage(Document document) {
myNewPage = true;
document.newPage();
myNewPage = false;
}
Now whenever you want to trigger a new page, don't use:
document.newPage();
Use this instead:
event.newPage(document);
The onStartPage() method will be called internally for every new page that is initialized, and at that moment, the value of myNewPage will be true whenever the newPage() was triggered by yourself; otherwise it will be false.
I hope this helps; I didn't test it, I'm just telling you what I would try.
(PS: I'm the original developer of iText.)
I'm trying to handle the event when the close button of a Window is clicked:
// View Code
#Override
public void attachWindowListener(WindowListener listener) {
window.addWindowListener(listener);
}
// Presenter code
view.attachWindowListener(new WindowListener(){
public void windowHide(WindowEvent we) {
GWT.log("Window Event - Processing fields");
processFields();
}
});
However, the windowHide function seems to be not executed since I can't see the log I placed there.
How to properly handle that event?
How about
Window.addCloseHandler(
new CloseHandler<Window>()
{
public void onClose( CloseEvent<Window> windowCloseEvent )
{
// Do your worst here
}
} );
I usually put this in onModuleLoad() in my EntryPoint class.
Cheers,
Based on the information provided I would guess that either a.) the events you think are firing do not fire for the Window component (even if it seems like they should) or b.) the events are firing but in a different order than you expect.
For example, it's possible that a BrowserEvent or some other event is firing first as the window is being closed and the Window object's WindowEvent never fires. According to the API docs for GXT 2.x, the WindowEvent will fire on hide and deactivate but it does not specify that it fires on close. The GXT 3.0.x API doc is less clear on this point but I would assume the same behavior. Unfortunately Sencha does not provide good documentation on what events fire for a given component and in what order.
With that said, I have had some luck working through similar issues to this by using a debug class which outputs all the events on a component to which it is attached. This may shed some light on which events are firing and their order of execution, and you may find an optimal event to which you can attach your processFields() method.
For a good example of a debugger class, see this answer from a related post: https://stackoverflow.com/a/2891746/460638. It also includes an example of how to attach the debugger to your component.
API Doc for Window, GXT 2.x: http://dev.sencha.com/deploy/gxt-2.2.5/docs/api/com/extjs/gxt/ui/client/widget/Window.html
API Doc for Window, GXT 3.0.x: http://dev.sencha.com/deploy/gxt-3.0.0/javadoc/gxt/com/sencha/gxt/widget/core/client/Window.html
This worked:
window.addListener(Events.Hide, new Listener<ComponentEvent>() {
#Override
public void handleEvent(ComponentEvent be) {
// Do stuff
}
});
I am using a SuggestBox and trying to capture the SuggestionEvent that is fired when the user selects a Suggestion. I can do this with normal event handlers easily enough:
itemInputBox.addEventHandler(new SuggestionHandler() {
#Override
public void onSuggestionSelect(SuggestionEvent event) {
Window.alert(event.getSelectedSuggestion().getReplacementString());
}
});
That works fine, event fires with the correct replacement string. However, I like to use UiHandler whenever possible due to how much cleaner the code is. So I've tried the following:
#UiHandler("itemInputBox")
void onSuggestionSelect(SuggestionEvent event) {
Window.alert(event.getSelectedSuggestion().getReplacementString());
}
But this results in the following errors:
[WARN] [jsonp] - Method 'getAssociatedType()' could not be found in the event 'SuggestionEvent'.
[ERROR] [jsonp] - Parameter 'SuggestionEvent' is not an event (subclass of GwtEvent).
I have a different UiHandler working correctly on the same SuggestBox so I am kind of confused where I'm going wrong:
#UiHandler("itemInputBox")
void onKeyUp(KeyUpEvent event) {
Window.alert("Key up event firing.");
}
I don't understand why one UiHandler fires correctly, while the other results in a error.
SuggestionEvent does not extend GwtEvent instead it extends java.util.EventObject.
This is why it will not work with UiBinder. I will bring this up on the GWT contributer list to see if there is a specific reason for this. Right now I am just guessing that it was forgotten when moving to the new event system.