How to call GWT client code from within a GQuery event handler? - gwt

I'm learning GQuery. It seems cool, but also a little confusing.
I have the following GWT client code. The selected item fades out, nicely. But the delete method never gets called. There is no error. It's very odd.
Is it even possible to call non-GQuery functions from inside a GQuery method?
delete.addClickHandler( new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
$(myIndicator).fadeOut(500, new Function(){
#Override
public void f() {
super.f();
delete();
}
});
}
});
And the delete method is:
private void delete() {
removeFromParent();
ruleDeleteRequestEvent.fire(new RuleDeleteRequestEvent(ruleBinder.getModel()));
}

Do not call super.f(), if so the default implementation of Function.f() will throw an Exception preventing the next line be executed (take a look to the source code) .

Related

GWT Button Click Enable/Disable Pattern -- GwtEvent assertLive() in dev mode

To avoid users clicking repetitively on the same button and by the same token send multiple requests to server, I have used the following pattern:
In button ClickHandler.onClick, disable the button.
In call back, re-enable the button.
See pattern in code below. The "rpcCall" function below basically is the core implementation of the Button onClick(final ClickEvent event).
private void rpcCall(final ClickEvent event)
{
final AsyncCallback<Void> callback = new AsyncCallback<Void>()
{
#Override
public void onSuccess(Void result)
{
final Button source = (Button) event.getSource(); // Dev mode isLive assertion failure.
source.setEnabled(true);
// Process success...
}
#Override
public void onFailure(Throwable caught)
{
final Button source = (Button) event.getSource();
source.setEnabled(true);
// Process error...
}
};
// Disable sender.
final Button source = (Button) event.getSource();
source.setEnabled(false);
// RPC call.
final RpcAsync rpcAsync = getRpcAsync();
RpcAsync.rpcCall(..., callback);
}
I just noticed a "This event has already finished being processed by its original handler manager, so you can no longer access it" exception caused by an isLive assertion failure in dev mode when the onSuccess async function calls event.getSource().
It seems to work in production/javascript mode though.
This dev mode assertion failure makes me question this pattern.
Is it a good pattern? Why do I get the exception only in dev mode? What would be a better pattern?
Obviously, I could bypass the call to event.getSource() by passing the source Button as an argument of the rpc wrapper call function, but it seems redundant with the event object already carrying such a reference.
Historically, the way you got the event object in IE was to use window.event, which only lasted the time to process the event. GWT's Event object therefore had to put guards so you're discouraged to keep a hold on an event instance, as it could suddenly reflect another event being processed, or no event at all (weird!)
Fortunately, Microsoft has since fixed their browser, and this is why it works when you test it (I bet you didn't test in IE6 ;-) ).
The correct way to handle that situation is to extract all the data you need from the event and keep them in final variables:
private void rpcCall(final ClickEvent event)
{
final Button source = (Button) event.getSource();
final AsyncCallback<Void> callback = new AsyncCallback<Void>()
{
#Override
public void onSuccess(Void result)
{
source.setEnabled(true);
// Process success...
}
#Override
public void onFailure(Throwable caught)
{
source.setEnabled(true);
// Process error...
}
};
// Disable sender.
source.setEnabled(false);
// RPC call.
final RpcAsync rpcAsync = getRpcAsync();
RpcAsync.rpcCall(..., callback);
}

GWT is making an unexpected event call

My code is below: I am seeing that on running the app the loadWidget method gets invoked even when the adminLink is not clicked. This is not want I want, but I'm not sure what is causing the issue. Please advise
public class LoginModule implements EntryPoint {
LoginPopup loginPopup;
private class LoginPopup extends PopupPanel {
public LoginPopup() {
super(true);
}
public void loadWidget(){
System.out.println("I am called 1");
CommonUi cUi = new CommonUi();
//#342 moved code to common area
FormPanel loginForm = cUi.getLoginFormUi();
setWidget(loginForm);
}
}
#Override
public void onModuleLoad() {
//#251 improved login popup ui.
final Anchor adminLink = new Anchor("User Login");
// final Label adminLink = new Label("User Login");
adminLink.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
// Instantiate the popup and show it.
loginPopup = new LoginPopup();
loginPopup.loadWidget();
loginPopup.showRelativeTo(adminLink);
loginPopup.show();
}
});
if(RootPanel.get("admin") !=null)
RootPanel.get("admin").add(adminLink);
}
}
Running Dev Mode, set a breakpoint in that method in your Java IDE, and take a look at the current stack, what code is calling that method. If that is the only code in your app, then this only appears to be invokable from that onClick handlers, so it is a matter of figuring out why that is being invoked.

Using drag mouse handlers with GWT canvas

I am currently developing a paint-like application for GWT. I would like to add a mouse handler that runs when the user drags the mouse across the canvas(like making a square,etc;), the problem is that I'm not surewhat handler to use. Looking through the handlers implemented in canvas has lead me to some hints, but the documentation as to what event the apply to is scant.
Does anyone know how I should implement it? Thanks.
There is no "dragging" handler. You imlement "dragging" with MouseDown, MouseMove and MouseUp events.
class YourWidget extends Composite
{
#UiField
Canvas yourCanvas;
private boolean dragging;
private HandlerRegistration mouseMove;
#UiHandler("yourCanvas")
void onMouseDown(MouseDownEvent e) {
dragging = true;
// do other stuff related to starting of "dragging"
mouseMove = yourCanvas.addMouseMoveHandler(new MouseMoveHandler(){
public void onMouseMove(MouseMoveEvent e) {
// ...do stuff that you need when "dragging"
}
});
}
#UiHandler("yourCanvas")
void onMouseUp(MouseUpEvent e) {
if (dragging){
// do other stuff related to stopping of "dragging"
dragging = false;
mouseMove.remove(); // in earlier versions of GWT
//mouseMove.removeHandler(); //in later versions of GWT
}
}
}
I've messed around with this as well and produced this little thing awhile ago:
http://alpha2.colorboxthing.appspot.com/#/
I basically wrapped whatever I needed with a FocusPanel. In my case it was a FlowPanel.
From that program in my UiBinder:
<g:FocusPanel ui:field="boxFocus" styleName="{style.boxFocus}">
<g:FlowPanel ui:field="boxPanel" styleName="{style.boxFocus}"></g:FlowPanel>
</g:FocusPanel>
How I use the focus panel (display.getBoxFocus() seen below just gets the FocusPanel above):
display.getBoxFocus().addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
}
});
display.getBoxFocus().addMouseDownHandler(new MouseDownHandler() {
#Override
public void onMouseDown(MouseDownEvent event) {
}
});
display.getBoxFocus().addMouseMoveHandler(new MouseMoveHandler() {
#Override
public void onMouseMove(MouseMoveEvent event) {
}
});
display.getBoxFocus().addMouseUpHandler(new MouseUpHandler() {
#Override
public void onMouseUp(MouseUpEvent event) {
}
});
// etc!
To answer your question about what handler to use for "dragging" I haven't found a single handler to do that for me. Instead I used a MouseDownHandler, MouseMoveHandler, and a MouseUpHandler.
Use the MouseDownHandler to set a flag that determines when the users mouse is down. I do this so that when MouseMoveHandler is called it knows if it should do anything or not. Finally use MouseUpHandler to toggle that flag if the user has the mouse down or not.
There have been some flaws with this method (if the user drags their mouse off of the FocusPanel), but because my application was just a fun side project I haven't concerned myself with it too much. Add in other handlers to fix that if it becomes a big issue.

not able to set focus on TextBox in a GWT app

This should not be causing me so much pain but it is. It is a very weird problem. In a GWT application, I have two .java files, login.java and application.java.
In login.java, I'm creating a user login page where if the username and password is verified the user is logged into the application and application.java takes from here.
Now in application. java's onModuleLoad() this is how i'm starting with a login page.
public void onModuleLoad() {
Login login = new Login();
login.textBoxUsername.setFocus(true);
RootLayoutPanel.get().add(login);}
This works great, except for the tiny problem of not being able to set focus on the username TextBox when the page loads. I have tried evrything I can think of. But the focus just doesn't get set on the TextBox. If anyone can suggest a solution, please do. Your help is greatly appreciated.
Solution: (In case it helps anyone facing the same issue)
final Login login = new Login();
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
public void execute () {
login.textBoxUsername.setFocus(true);
}
});
RootLayoutPanel.get().add(login);
Try using Scheduler.scheduleDeferred():
public void onModuleLoad() {
Login login = new Login();
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand () {
public void execute () {
login.textBoxUsername.setFocus(true);
}
});
RootLayoutPanel.get().add(login);
}
Update: answer updated to use Scheduler.get().scheduleDeferred() instead of DeferredCommand, which is deprecated.
Why using DefferedCommand, I think it's better to use someWidget.getElement().focus() which is a native Javascript. I'm using it everywhere, I've not seen any problem.
If your Widget extends Composite, you can:
#Override
protected void onAttach() {
super.onAttach();
textBoxUsername.setFocus(true);
}
It would be so easy for GWT to store a 'wantsFocus' in the internal state, and call focus after the widget is attached. We are still waiting after many years for that feature however...
Still, even after the attach handler is called, setFocus does not always work.
So in the meantime, our GwtUtil library has used the following code. It is a combination of several other solutions, and has been wrapped in a utility function:
static public void setFocus(final FocusWidget focusWidget) {
if (focusWidget.isAttached()) {
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
#Override
public void execute() {
focusWidget.setFocus(true);
}
});
} else {
focusWidget.addAttachHandler(new AttachEvent.Handler() {
#Override
public void onAttachOrDetach(AttachEvent event) {
if (event.isAttached()) {
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
#Override
public void execute() {
focusWidget.setFocus(true);
}
});
}
}
});
}
}
And call it like this:
setFocus(myTextBox);
It makes sense to use a utility function; If and when GWT finally makes setFocus work, you won't have to change your source code in multiple places.

How to intercept the onSuccess() method in GWT

I need to do method interception for the onSuccess method in GWT.
I need to add some code before and after the calling of the onSuccess method in GWT? (I have many calls to the onSuccess method and I need to do this dynamically)
EDIT:
I need to add a progress bar in the right corner of the screen, that appears when the code enters the onsuccess method and disappears on the exit of onsuccess method.
From a visual perspective
void onSuccess(Value v) {
showProgressBar();
doLotsOfWork(v);
hideProgressBar();
}
will be a no-op. Browsers typically wait for event handlers to finish executing before re-rending the DOM. If the doLotsOfWork() method takes a noticeable amount of time to execute (e.g. >100ms) the user will notice the browser hiccup due to the single-threaded nature of JavaScript execution.
Instead, consider using an incrementally-scheduled command to break the work up. It would look roughly like:
void onSuccess(Value v) {
showProgressBar();
Scheduler.get().scheduleIncremental(new RepeatingCommand() {
int count = 0;
int size = v.getElements().size();
public boolean execute() {
if (count == size) {
hideProgressBar();
return false;
}
processOneElement(v.getElements().get(count++));
setProgressBar((double) count / size);
return true;
}
});
}
By breaking the work across multiple pumps of the browser's event loop, you avoid the situation where the webapp becomes non-responsive if there's a non-trivial amount of work to do.
Well, it is a generic non-functional requirement, I have done some research on this item, I have implemented a solution that Thomas Broyer has suggested on gwt group.. This solution has distinct advantage over other suggested solutions, You dont have to change your callback classes, what you have to do is just add a line of code after creation of async gwt-rpc service...
IGwtPersistenceEngineRPCAsync persistenceEngine = GWT.create(IGwtPersistenceEngineRPC.class);
((ServiceDefTarget) persistenceEngine).setRpcRequestBuilder(new ProgressRequestBuilder());
import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.rpc.RpcRequestBuilder;
public class ProgressRequestBuilder extends RpcRequestBuilder {
private class RequestCallbackWrapper implements RequestCallback {
private RequestCallback callback;
RequestCallbackWrapper(RequestCallback aCallback) {
this.callback = aCallback;
}
#Override
public void onResponseReceived(Request request, Response response) {
Log.debug("onResposenReceived is called");
// put the code to hide your progress bar
callback.onResponseReceived(request, response);
}
#Override
public void onError(Request request, Throwable exception) {
Log.error("onError is called",new Exception(exception));
// put the code to hide your progress bar
callback.onError(request, exception);
}
}
#Override
protected RequestBuilder doCreate(String serviceEntryPoint) {
RequestBuilder rb = super.doCreate(serviceEntryPoint);
// put the code to show your progress bar
return rb;
}
#Override
protected void doFinish(RequestBuilder rb) {
super.doFinish(rb);
rb.setCallback(new RequestCallbackWrapper(rb.getCallback()));
}
}
You cant do that. The rpc onSuccess() method runs asynchronously (in other words, depends on the server when it completes, the app doesnt wait for it). You could fire code immediately after the rpc call which may/ may not complete before the onSuccess for RPC calls.
Can you explain with an eg why exactly do u want to do that? Chances are you might have to redesign the app due to this async behavior, but cant say till you provide a use case. Preferably any Async functionality should be forgotten after the rpc call, and actioned upon only in the onSuccess.