GWT event handling. Needs to block the event till form submit finish - gwt

I'm developing a wizard by using GWT. In the Wizard first page i have a form component to upload the file. In the wizard panel i have the next button when i press the next button the validation method will be triggered if the validation is passed then i'm calling the form.submit(); but before form.submit() handler starts the functionality the validation methods completes it. After it completes the validation method only the form submit it's really taking part. How can i controll this event behavior, when i submit the form using form.submit() the remaining actions has to wait till this form returns to it's handler.
Advance Thanks.

Assuming you have a FormPanel:
FormPanel form = new FormPanel();
You can add a handler:
form.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
public void onSubmitComplete(SubmitCompleteEvent event) {
// TODO: Do the next step in the wizard
// Use event.getResults() to get the text of the response
}
});

Write a boolean which you'll set to true once the validation is complete. Then start a timer that waits on that boolean. But consider using events and callbacks for repeated use. Using timer will make your code messy if you overuse them.
#UiHandler("submit")
protected void onSubmit() {
validated=false;
validate();
Scheduler.get().scheduleFixedDelay(new RepeatingCommand() {
public boolean execute() {
if (validated) {
if (validationSucceeded()) {
submit();
}
return false;
}
return true;
}
}, 250);
}
private boolean validated = false;
private void validate() {
// do validation
validated=true;
}

Related

Can't submit on dropdown lazy loading

My form has 1 dropdown use AjaxLazyLoadPanel and 1 ajax button submit.
I click button submit that works only when the dropdown is finished loading.
Index.java
form.add(new AjaxLazyLoadPanel("lazy") {
private static final long serialVersionUID = 1L;
#Override
public Component getLazyLoadComponent(String markupId) {
Fragment fr = new Fragment(markupId, "lazyContentFragment", Index.this);
fr.add(dropdown());
return fr;
}
});
form.setOutputMarkupId(true);
form.add(new AjaxButton("search") {
#Override
protected void onError(AjaxRequestTarget target) {
target.add(feedback);
}
#Override
protected void onSubmit(AjaxRequestTarget target) {
//do something...
}
});
Index.html
<form wicket:id="form">
<input wicket:id="textbox"/>
<div wicket:id="lazy"></div>
<button wicket:id="search"></button>
</form>
<wicket:fragment wicket:id="lazyContentFragment">
<select wicket:id="dropdown"></select>
</wicket:fragment>
Is there any way to submit the form without waiting for the dropdown finish loading.
By default wicket-ajax.js serializes the Ajax calls to the server. This is being done so that the second Ajax call is not called if its HTML element is being removed/painted by the first Ajax call.
In addition only one thread can manipulate a Page instance at a time at the server side!
To be able to make two Ajax calls at the same time you need to use different AjaxChannels for them. For example:
... = new AjaxButton("someId") {
#Override protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
{
attributes.setChannel(new AjaxChannel("customName"));
}
}
This way both Ajax requests will be fired to the server, but the AjaxButton's one will be processed only after the AjaxLazyLoadingPanel's one releases the lock on the page instance at the server side. There is no way to execute two threads on the same page instance (i.e. having the same pageId).
If you're dropdown's choices are taking so long to load, you might want to make your AjaxLazyLoadPanel asynchronous by overriding #isContentReady():
private String token;
private List<T> choices;
protected boolean isContentReady()
{
if (token == null) {
token = startLoadingChoices();
} else {
choices = checkChoicesLoaded(token);
}
return choices != null;
}
Since Wicket manages and serializes all pages, your page must not be held as a reference in a thread or a listener in central registry. Keep a token instead and ask for the loading result; #isContentReady() will be polled repeatedly until it returns true.

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

continuous actions to be performed when I long tapped MGWT button until the touch end event fired

I want to invoke a method continuously when I used MGWT button long tap handler, this should be done until I release the button. i.e; until the touch end event fired. For this I had written Timer inside the MGWT Button's long tap handler.I continuously calling the my task method inside the run method of the Timer. my code:
upButton.addLongTapHandler(new LongTapHandler() {
#Override
public void onLongTap(LongTapEvent event) {
upBtnTimer = new Timer() {
#Override
public void run() {
if(getValue() >= maxValue){
Window.alert("max val reached");
upBtnTimer.cancel();
}else{
setValue(getValue() + RATE);
}
}
};
upBtnTimer.scheduleRepeating(100);
}
});
And I also wrote touch end handler to the upButton. this is:
upButton.addTouchEndHandler(new TouchEndHandler() {
#Override
public void onTouchEnd(TouchEndEvent event) {
if(upBtnTimer!=null){
upBtnTimer.cancel();
upBtnTimer = null;
}
}
});
this is OK when I'm testing my mobile application on browser, but when I installed my application in iOS/Android device, this is not working. Only single tap event firing.
If you are clear with my requirement please tell me if there is another approach to do this. Thanks in advance.

GWT Delaying an action after an event trigger

I want to have the user click a button, then they will see a "Toast" message popup, which fades away , then the action that the button click performs should happen. What is the best way to do this? Should I trigger a Timer on catching the click event and let it timeout (While the toast is being displayed ) and then call the handling code or is there any built in delay mechanism in event handling I can use?
I don't want my toast to be involved at all in the event handling
If I really follow your requirements the following code should do:
// interface of the "Toast" no matter what the implementation actually is
public interface Toast
{
void open( String message );
void closeFadingAway();
}
// calling code
public class ClientCode
{
private static final int myDelay = 1000; // 1 second in millis
private Toast myToast;
void onMyAction()
{
myToast.open( "Your action is being handled..." );
Scheduler.get().scheduleFixedDelay( new RepeatingCommand()
{
#Override
public boolean execute()
{
myToast.closeFadingAway();
performAction();
return false; // return false to stop the "repeating" = executed only once
}
}, myDelay );
}
void performAction()
{
// do something interesting
}
}
Now, if you actually mean to be able to interrupt the action when the user presses some button in the toast this is a different story.
If you are using a popup panel you could use the addCloseHandler on the popup panel and from here call the method that would have otherwise been called by the button.
popUpPanel.addCloseHandler(new CloseHandler<PopupPanel>(){
#Override
public void onClose(CloseEvent<PopupPanel> event) {
// TODO Do the closing stuff here
}
});
So when the PopupPanel disappears and the close event triggers you can do your magic there.

Firing ListGrid selection item on GWT

When the user clicks a button, I want to fire the ListGrid Selection event. I called "resultControl.resultGrid.selectRecord(0);" but it didn't work.
From your initial question and your comment, I understand that you want to simulate a selection event in your ListGrid, through a button. Assuming that I understand well, and you are only interested in one record selection (the first one), all you have to do is the following:
final ListGrid listGrid = new ListGrid();
//Initialize your listgrid's data etc.
listGrid.addSelectionChangedHandler(new SelectionChangedHandler() {
#Override
public void onSelectionChanged(SelectionEvent event) {
SC.say("here my code");
}
});
IButton button = new IButton("Select");
button.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
listGrid.selectRecord(0);
}
});
A last note, System.out or System.err won't produce anything when your application runs in production mode. Use a suitable logging solution or the SC.say(), if you want to provide the user with a message, instead.