How can I centralize management of a "loading" icon for GWT async RPC calls? I'm looking for a way to have every async call automatically kick off a timer. When the timer fires, if the RPC has not yet completed, a "loading" icon should be displayed. When the RPC completes (either onSuccess()
or onFailure()
) the loading icon should be removed.
It's tedious to do this manually for each call, and in fact quite easy to get it wrong and leave the user with a stuck UI.
Could generators be used for this? Just to be clear- I'm not looking for code to display a dialog or icon; I'm looking for a way to centralize management of such a dialog/icon.
Maybe I look at it in a more simple way. But we have similar behavior in our applications and we just implement it using a decorator pattern. The decorator takes care of showing the loading UI (in our case it shows right away), and on return makes sure that the UI is removed again.
Our invocations look a bit like this:
rpc.dosomething( params, Modality.appModal( new AsyncCallback<String>() {
public void onSuccess( String pValues ) {
... handle success ...
}
public void onFailure( Throwable pCause) {
... handle failure ....
}
}));
Modality.appModal returns an AsyncCallback that does the UI part and after success or failure dispatches to the AsyncCallback given as parameter in the invocation.
Is it worth going further with code generators ? It is implemented once and used everywhere without further thinking.
David
I resolved this issue by creating an util class for ajax calls. This class contains a loadingIndicator and a callstaack. The loadingIndicator is the PopupPanel that will display the message. The callstack is a static list that contains all the actual AsyncCallback objects that need a loading indicator. When the callback happens (success or error) the callback is removed from the list. The loading indicator will be hidden only if there is no callback left in the list.
public class Ajax {
private static final PopupPanel loadingIndicator = WidgetFactory.createLoadingPopup();
private static final List<AsyncCallback<?>> callstack = new ArrayList<AsyncCallback<?>>();
public static <T> AsyncCallback<T> call(final AsyncCallback<T> callback) {
if(!loadingIndicator.isShowing()){
loadingIndicator.center();
}
callstack.add(callback);
return new AsyncCallback<T>() {
@Override
public void onFailure(Throwable caught) {
handleReturn();
callback.onFailure(caught);
}
@Override
public void onSuccess(T result) {
handleReturn();
callback.onSuccess(result);
}
private void handleReturn(){
callstack.remove(callback);
if(callstack.size() < 1) {
loadingIndicator.hide();
}
}
};
}
}
And then I use it for evervry RPC calls that needs a loading indicator like this:
myService.myMethod(Ajax.call(new AsyncCallback<MyReturnType>() {
@Override
public void onFailure(Throwable caught) { ... }
@Override
public void onSuccess(MyReturnType result) { ... }
}));
You can find some answers here: Automatic ‘loading’ indicator when calling an async function.
I agree with others on this page that it is not worth using code generators for this.