GWT How discard changes on a Editor - gwt

I there a way of Editor discards changes made on its properties? This on client side. No persitence.
I have:
public class ClaseEditor extends PopupPanel implements Editor<ClaseProxy> {
#UiField ValidatedTextBox tema;
#UiField ValidatedTextBox catedratico;
}
I use this editor on a ListEditor as u know there are a list of editors in your
ListEditor<ClaseProxy, ClaseEditor>
If user create one, its okay, then if user edit it. i have a save or cancel options, i save ok, just hide the editor and changes made are ok.
But in user clicks Cancel and if there was some changes on the properties the editor flush(lazely) that changes to the proxy.
Yes i can store the start value on a string then restore with setValue() on the texboxes. But there is some other way (Editor API) that prevents this?
Thank you

If you are using a SimpleBeanEditorDriver, you can do a new call on the edit method, without calling flush first.
The SimpleBeanEditorDriver class reads from the bean into the editors on edit, and from the editors into the bean on flush.
If you don't want to revert all the editors, but only one of them, remember to call flush on every accepted editor change, in order to be able to restore to the last flush point. Note that a flush call is local and doesn't necessarily have to correspond to a call to the persisting layer.
Example code
private Bean currentObject;
/**
* Start editing the given object.
*/
public void edit(Bean object) {
this.currentObject = object;
this.driver.edit(object);
}
/**
* Call this every time an editor is in a consistent state.
* (e.g. onBlur event if validation succeeds)
*/
private void save() {
this.driver.flush(); // saves editors' state into currentObject
}
/**
* Call this to cancel changes on all editing editors.
* (e.g. onBlur event if validation fails)
*/
private void revert() {
this.driver.edit(currentObject); // reloads currentObject into editors
}
/**
* Stores all pending changes to the server.
* Remember to validate all editors.
*/
public void commit() {
Bean object = this.driver.flush();
Server.persist(object);
}

Yes. On the cancel button, do a fire() without building any request. What the editor does never effects the original proxy, it is immutable. The flush only gives you a copy (unless you are using the RequestFactoryEditorDriver then it returns the context you sent into it with the driver.edit(proxy,ctx) . The fire() without a request clears the edit proxy copy if the user wants to edit again it won't get an error that it is already being editted.

Related

RelayCommand for handling changes in TextBox

I am new to MVVM and MVVM-light.
I always see RelayCommand being used to handle Button's Command action. So it will invoke a service operation aysnc.
My question is how can I use it to handle TextBox changes in the text it is holding? How can I relay that change to the Server side using service? Should I use RelayCommand too?
Typically it's not needed. If you bind the TextBox Text property to a member of your viewmodel and set its UpdateSourceTrigger to PropertyChanged then your bound member will get called as soon as the value of the textbox changes i.e. whenever the user presses a key:
private string _myString;
public string MyString
{
get { return this._myString; }
set { this._myString = value; /**** user pressed a key, respond to it here *****/}
}
It's also possible to set up an Event Trigger and intercept the windows messages directly, but I suspect that's not really what you need here.

Unknown reference to GWT widget prevents clearing of detached DOM tree

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

GWT input event on TextBox

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;
}
}

Handle Window close event

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

pause viewmodel process for user input

I've been looking at a view examples of the typical "raise dialog from viewmodel" problem, noting 3 main solutions:
use attached behaviors
use a mediator pattern
use a service
I'm getting a bit bogged down though and struggling to find a solution that easily fits into my problem space - which is a very simple file copy problem:
My viewmodel is processing a loop (copying a list of files)
When a file already exists at the destination I need to raise a modal dialog to get confirmation to replace
The vm needs to wait for and receive confirmation before continuing
The "modal dialog" is actually not a new window but a hidden overlay in my MainWindow, as per http://www.codeproject.com/KB/WPF/wpfmodaldialog.aspx (thanks Ronald!)
I'm mostly there but the biggest struggles I have are:
- how to pause the loop in the viewmodel while it waits for input
- how to get input back to the viewmodel within the loop so it can carry on
So far I'm leaning towards the service solution because it seems a direct method call with a return that the vm must wait for. However, it does mean the service needs to tie directly to the view in order to make an element visible?
If anyone can post some simple code that deals directly with this problem I (and the net) would be very happy! Thanks!
For example, you have a service called IDialogService with the following interface:
public interface IDialogService
{
bool ConfirmAction(string title, string confirmationText);
}
As you mentioned, in order for the service to be able to show the actual dialog it needs to have a reference to the view that will show the actual overlay element. But instead of directly referencing the view I prefer to reference it via an interface. Lets call it ICanShowDialog and it will have the following members:
public interface ICanShowDialog
{
void ShowDialog(object dialogContent);
void HideDialog();
}
This interface will be implemented by your view that owns the dialog overlay (e.g. your main window).
Now the interesting part: suspending the code execution while the dialog is shown. First of all, I would recommend you not to use overlay elements but use usual windows if possible. Then you will not have that problem. You can style the dialog window so it will look just like the overlay element.
Anyway, if you still want to use overlay elements then you can do the following trick to suspend the code execution:
Here is pseudo code of the ConfirmAction method of the IDialogService inteface:
public bool ConfirmAction(string title, string confirmationText)
{
ConfirmationDialogView dialogView = new ConfirmationDialogView(title, confirmationText);
DialogShower.ShowDialog(dialogView); // DialogShower is of type ICanShowDialog
while (!dialogView.ResultAvailable)
{
DispatcherUtils.DoEvents();
}
DialogShower.HideDialog();
return dialogView.Result;
}
Here is the code of DispatcherUtils.DoEvents() (that was taken from here: http://dedjo.blogspot.com/2007/08/how-to-doevents-in-wpf.html):
public static class DispatcherUtils
{
public static void DoEvents()
{
DispatcherFrame f = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(
DispatcherPriority.Background,
(SendOrPostCallback)delegate(object arg) {
DispatcherFrame fr = arg as DispatcherFrame;
fr.Continue=True;
}, f);
Dispatcher.PushFrame(frame);
}
}
But I must warn you. Using DoEvents can result in some subtle bugs caused by inner dispatcher loops.
As an alternative to suspending the code execution while a dialog is shown you can use callbacks:
public interface IDialogService
{
void ConfirmAction(string title, string confirmationText, Action<bool> dialogResultCallback);
}
But it will not be so convenient to use.