Problems with multiple click on a button

Hi, is it possible to disable multiple clicks on the same button while the server is running the request?

In our case we have a button that generates a report that takes typically 15-20 seconds to generate. As we have quite a few users that are not of the most patient type they will click the button again as there is no immediate result.

If I understand the underlying architecture correctly, this new request will be queued and then sent to the server when the previous request completes? Is it possible to override this behavior? In simple HTML we would either disable the button with javascript and/or enforce this with a servlet filter checking if there is already an undergoing action. However, we are not able to do this now as requests come in to the server back-to-back as they do now.

There have to be others who have the same problem as us, even if it is just to control if a user has double-clicked a button instead of a single click. Some operations in our application will also behave differently if run twice instead of once (transactions generated two times for instance).

Thanks!

One way to deal with it which otherwise also might be appropriate if the action takes 15-20 seconds is to show a “Please wait” popup, add a ProgressIndicator to the popup and start the processing on the server in a background thread (and additionally disable the button if you want). The click request to the server will then almost immediately return and the user will get feedback that something is happening. When the processing has finished you update the UI with the results and remove the popup and the ProgressIndicator.

Hi, we’ve considered this, but we’re not quite comfortable with it. First of all, we need to add rather cumbersome and unnecessary threading code to our rather simple application code adding complexity where it really should not need be. Secondly we will have to do this a lot of places in our code, making reuse harder as well.

In addition to this, it can not guarantee to solve a user’s fast double click, this will still end up with two separate requests to the server as the clicks may be fast enough in succession as the button will not become disabled fast enough.

We “solved” the first problem (re-click after a while) by adding the following to our css files:

.v-loading-indicator-wait, .v-loading-indicator-delay, .v-loading-indicator{
height: 100%;
width: 100%;
background-repeat: no-repeat;
background-position: top right;
cursor: wait;
}

This will probably pose a problem in IE6, but we can guarantee that our users use IE8, so no problem there.

The double-click issue, however, persists. Is there really no solution for this?

If there is no solution for this as-is, would it be possible to add support for this in the framework? Double-click-prevention on buttons has to be a problem more people need a solution for?

Thanks!

Don’t know if there are reasons not to have a general solution, but it does seem “standard” or “typical” that when a button is pressed, it could be automatically grayed out (disabled) until some response from the server is received. It might not solve all such issues, but when long running processes are needed, you could still fall back to disabling the button yourself, adding a progress meter, modal dialog, or what not, but that’s rare and harder to code for most requests.

Since buttons are immediate, it seems like pressing one should not allow more presses/actions until some response from the server occurs. Of course, this may be easier said than done.

I don’t know what it would mean, but in our old JSP world, we used to have javascript that would hide all input/type=submit buttons once any button was pressed since that would remain hidden until the JSP response page was shown. Is something similar to that possible in a Vaadin UI?

My point exactly.

We tried the solution of manually making the button disabled from the java code and then spawn another working thread. However, there is simply no chance that this operation is fast enough to avoid double clicks (and if it was in our test environment, it could definitely not guarantee it for all instances).

So basically what we need is a way to set the property on a button (or a form) to disable button(s) while loading on the server. Shouldn’t be too hard to implement either.

In good old (yeah, I’m one of those…) times, a simple $(input[type=button]
).attr(“disabled”, true); would suffice… Then set it to false when the callback (or timeout) is run…

So in Vaadin/GWT that would be something like:

public class VDisableButton extends VButton {

    @Override
    public void onClick(ClickEvent event) {
        setEnabled(false);
        super.onClick(event);
    }
}

@com.vaadin.ui.ClientWidget(VDisableButton.class)
public class DisableButton extends Button {

    // Constructors go here

}

Note that this only disables the button when it is clicked. In order for it to be enabled again you need to ensure it is repainted after a click e.g. by calling requestRepaint() for the button in the click listener

That sounds like a viable solution. Vaadin should include this from the get-go however, so consider this a feature request. Is it possible to add a ticket regarding this?

Sure, just create a ticket at
http://dev.vaadin.com

Created ticket :
http://dev.vaadin.com/ticket/6444

Greetings,

im developing vaadin portlets right now.
the problem is that the buttons i’ve added in the application, when i click on them, the click event is triggered twice.

i’ve read about this issue on internet and i tried some ideas:

  • controlling user clicks with an counter (int)
  • removing click listener before adding new one
  • repainting button (and window too) for re-rendering

none of these ideas worked with vaadin.

any ideas???

Button.setDisableOnClick(boolean) was committed to the 6.7 branch today so be sure to check out the next nightly for this feature.

Multiple clicks spread out over time are one thing, but what about double clicks? If a user double clicks on a button we should only get one click event, but currently we get 2 click events. I hope that Vaadin should be smart enough to deal with that without requiring developers to use this setDisableOnClick method, and then to write the listener code to reenable the button.

Also, what about buttons that should no longer be clickable after the first click due to a modal that should come up after the first click? E.g. right now we have a button that when clicked pops up a modal. If the user double clicks, then the listener method is invoked twice and we are getting two modals (both up at the same time). Vaadin should be smart enough to behave correctly and ignore the second click. I would think that Vaadin should be ignoring the second click in general. But more specifically in this case Vaadin should ignore events on elements that are not on modals, when the modal is up. Having to use setDisableOnClick in this case would constitute a hack in my opinion.

One way that Vaadin does behave correctly is if the button disappears between clicks. In that case, Vaadin is correctly ignoring the second click. E.g. we have a button on a modal, and when the button is double clicked a listener closes the modal. Vaadin is smart enough to not invoke the listener method twice in this case because the button no longer exists in the UI after the first click event.

As my colleague says above Button.setDisableOnClick() is a step in the right direction but it’s less than ideal. Also it doesn’t handle the case where you have two different action buttons (e.g. save and cancel). With this solution you can immediately disable the save button but the user could still click on the cancel button.

Is there any recommended approach for disabling all AJAX calls until the inflight one completes?

Even disabling AJAX calls while waiting for a call to complete probably would not have the result you want.

One thing to test: perhaps one could write an Extension that temporarily disables listed components/widgets on the client side when it intercepts a click on the component it is extending (on one of the listed components if registered on a higher level layout). I’m not sure if you can intercept the relevant events properly, but perhaps worth looking into if this is important to you.

Thanks Henri. It seems like this kind of functionality should be built into the framework as I imagine it’s a very common requirement (the save/cancel example). I don’t this this as being unique to our situation.

ZK has something like this already built-in:

http://books.zkoss.org/wiki/ZK_Component_Reference/Essential_Components/Button

Button.setAutodisable(String) is used to disable a button automatically, when it is clicked. It is useful to prevent the user from clicking it twice (and firing redundant requests), which is common if the request takes long to serve.
The simplest use is to specify it with self as follows. Then, the button is disabled when it is clicked.
{{{

}}}

If you’d like to disable several buttons, you could specify all of them in this property by separating with a comma. For example, the following disables both buttons, when one of them is clicked.

{{{

}}}

I would say that this is quite specific and the case of buttons disabling buttons would then only be one special case. Finding the general case to address is far from obvious, which is one of the reasons why I’d much rather see this as an add-on than in the core. If the add-on turns out to be useful and the API and supported features good, the feature might migrate to core sometime in the future as has happened to a number of other add-ons.

Then again, I would expect that in most applications the client-side buttons do not need to disable others as the server round trip should be fairly small and the server processes requests in order and can ignore extraneous requests in case the user manages to make one in that small time window. Applications with background processing triggered from user actions might need a little more careful consideration in some cases to preserve the in-order semantics or to otherwise deal with such conflicting requests, though.

But isn’t the whole purpose of using a framework to make common things easier and dare I say it transparent? Sure I could write some special logic in my button listener to check if save is in progress and ignore the cancel operation. I could probably come up with some fancy reusable button listener too but it would be more convenient if the framework provided some kind of facilities for this out the box. If it wasn’t a common requirement ZK would not have added it to their framework as they have.

This scenario in my opinion shows one of the warts between a real fat client and a simulated one due to latency issues.

What would be the poor man’s solution without writing a custom plugin (we are stuck on 6.x for the moment btw) to simulate the behavior I’m describing for “long” running save operations.

Can I return immediately on click, disable both buttons, and display a modal progress indicator as described earlier in this thread by Artur Signell. Is there a KB article that you could point to (I’m a PRO user)?

Thanks

Hi, I dont know if I need a separate thread, my question is similar to this. I need to disable a button and re-enable it, say in 2 seconds. I have tried using Thread.sleep and timer but it doesn’t work so far. With timer it seems like I need another event to refresh the UI. Basically I want users not to keep clicking a button which submit the same queries to the database.

Did you try myButton.setDisableOnClick(true)? This works well so that you can re-enable it in your buttonClick callback with myButton.setEnabled(true).