Calling $().button(state) enables a disabled button
Created by: seanthebean
I have a problem with the way the button setState method works.
I have a project in which I am using a bootstrap button in a modal dialog, where the button's click action is to submit the form to a given URL, then close the dialog, with no further action allowed on the dialog. The desired result is that once a user clicks the submit button, the button is immediately disabled and remains disabled until the dialog is destroyed, but in the meantime the button state gets updated to indicate the status of the save request (e.g., maybe "Processing...", "Saving...", "Saved", etc).
Bootstrap does not provide a good way to do this. The problem is that setting the button state to anything other than "loading" will enable the button after the current event stack has been processed.
(The only workarounds that I'm aware of involve a hack using setTimeout to set the "disabled" attribute again after it is enabled, or to set the text of the button without setting the state, neither of which is desirable.)
(This is a duplicate of https://github.com/twbs/bootstrap/issues/3034, but that issue was closed a year ago for lack of detail.)
A rough, simplified example of the problem do can be seen at: http://bootply.com/84160
The Bootstrap code in question is: https://github.com/twbs/bootstrap/blob/master/js/button.js lines 35-53, in the Button.prototype.setState method.
Also pasted at: http://codepaste.dev7studios.com/item/ml2kpybyn
The problem appears to be two-fold. One problem is that the code setting the disabled state of the button is located inside a call to setTimeout(function () {...}, 0), placing it at the end of the current event stack. The other is that setting the button to any state other than 'loading' will cause the button to be enabled. If either of these was fixed, the workaround would be easy.
I think the "best practice" solution would be to allow the devloper to control the enabled/disabled state of the button when setting the state, which could be easily accomplished one of two ways:
- Adding an additional parameter to the setState method. (Maybe a flag to indicate the button's state? Or an object defining additional options to set for the button?)
- Accepting an additional data attribute in the html for the button. For instance:
<button type="button" data-whatever-text="Whatever" data data-whatever-disabled="disabled">Rebellious Button</button>
being triggered by$('button').button('whatever')
would set the text to "Whatever" and disable the button