Disabling a button in vanilla JavaScript and in jQuery
Solution 1
To achieve expected result, you can utilize .isTrigger
within jQuery triggered click
handler to determine if event is triggered by javascript
, and not user action.
Define attribute event listener as a named function, where this
can be passed to check disabled
property at if
condition if alert()
is called, or not called.
Use .attr("disabled", "disabled")
to set disabled
at element, .removeAttr("disabled")
to remove attribute; .attr("onclick", null)
to remove event attribute onclick
handler; .attr("onclick", "handleClick(true)")
to reset event attribute.
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<input type="button" id="myButton" value="button" onclick="handleClick(this)" />
<script>
function handleClick(el) {
if (el.disabled !== "disabled")
alert("Hello")
}
var button = $("#myButton");
button.on("click", function(e) {
console.log(e);
if (e.isTrigger !== 3 && !e.target.disabled)
alert("world");
});
button.attr("disabled", "disabled");
button.attr("onclick", null);
button.click(); // no output
setTimeout(function() {
button.removeAttr("disabled");
button.attr("onclick", "handleClick(button[0])");
button.click(); // Output : "world" and "Hello"
// click button during 9000 between `setTimeout` calls
// to call both jQuery event and event attribute
}, 1000);
setTimeout(function() {
button.attr("disabled", "disabled");
button.attr("onclick", null);
button.click(); // no output
}, 10000);
</script>
Solution 2
If you take a look to jquery-1.12.4.js at these lines:
handlers: function( event, handlers ) {
var i, matches, sel, handleObj,
handlerQueue = [],
delegateCount = handlers.delegateCount,
cur = event.target;
// Support (at least): Chrome, IE9
// Find delegate handlers
// Black-hole SVG <use> instance trees (#13180)
//
// Support: Firefox<=42+
// Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343)
if ( delegateCount && cur.nodeType &&
( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) {
/* jshint eqeqeq: false */
for ( ; cur != this; cur = cur.parentNode || this ) {
/* jshint eqeqeq: true */
// Don't check non-elements (#13208)
// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) {
You will you see a different handling of events according to the delegation type:
$(document).on("click", '#btn', function() {
console.log("world");
});
$(function () {
$('#btnToggle').on('click', function(e) {
$('#btn').prop('disabled', !$('#btn').prop('disabled'));
});
$('#btnTestClick').on('click', function(e) {
$('#btn').click();
});
});
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<button id="btn">Click Me</button>
<button id="btnToggle">Enable/Disable button</button>
<button id="btnTestClick">Test Click</button>
Of course, if you attach the event like in:
$('#btn').on("click", function() {
alert("world");
});
The behaviour is different and seems strange.
John Slegers
I'm John Slegers, full stack web developer from Belgium. Prefered tech Stats Where to find me
Updated on June 05, 2022Comments
-
John Slegers almost 2 years
Vanilla JavaScript
In vanilla JavaScript, one can easily enable and disable a button using the following statement:
button.disabled = state;
This works both when humans try to click a button and when buttons are clicked programmatically:
var button = document.getElementById('myButton'); button.addEventListener('click', function() { alert('world'); }); button.disabled = true; button.click(); // No output button.disabled = false; button.click(); // Output : "Hello" and "world button.disabled = true; button.click(); // No output
<input type="button" id="myButton" value="button" onClick="alert('Hello')"/>
This also works when using the
MouseEvent
interface:var button = document.getElementById('myButton'); var click = new MouseEvent("click", { "view": window }); button.addEventListener('click', function() { alert('world'); }); button.disabled = true; button.dispatchEvent(click); // No output button.disabled = false; button.dispatchEvent(click); // Output : "Hello" and "world button.disabled = true; button.dispatchEvent(click); // No output
<input type="button" id="myButton" value="button" onClick="alert('Hello')"/>
jQuery
I can't seem to be able to do the same with jQuery, though :
var button = $("#myButton"); button.on("click", function() { alert("world"); }); button.prop("disabled", true); button.click(); // Output : "world" and "Hello" button.prop("disabled", false); button.click(); // Output : "world" and "Hello" button.prop("disabled", true); button.click(); // Output : "world" and "Hello"
<script src="https://code.jquery.com/jquery-1.12.2.min.js"></script> <input type="button" id="myButton" value="button" onClick="alert('Hello')"/>
Both
button.prop("disabled", true);
andbutton.attr("disabled", true);
simply change thedisabled
property of the button element, but neither disables the actual click event. This means that events are triggered wheneverbutton.click();
is called, even if the button is disabled!Additionally, "world" and "Hello" are output in the wrong order.
The simplest code I could come up with to emulate the behavior of the vanilla JavaScript versions, is this :
var button = $("#myButton"); button.on("click", function() { alert("world"); }); button.disable = (function() { var onclick = null; var click = []; return function(state) { if(state) { this.prop('disabled', true); if(this.prop('onclick') !== null) { onclick = this.prop('onclick'); this.prop('onclick', null); } var listeners = $._data(this.get()[0], "events"); listeners = typeof listeners === 'undefined' ? [] : listeners['click']; if(listeners && listeners.length > 0) { for(var i = 0; i < listeners.length; i++) { click.push(listeners[i].handler); } this.off('click'); } } else { this.removeProp('disabled'); if(onclick !== null) { this.prop('onclick', onclick); onclick = null; } if(click.length > 0) { this.off('click'); for(var i = 0; i < click.length; i++) { this.on("click", click[i]); } click = []; } } } })(); button.disable(true); button.click(); // No output button.disable(false); button.click(); // Output : "Hello" and "world button.disable(true); button.click(); // No output
<script src="https://code.jquery.com/jquery-1.12.2.min.js"></script> <input type="button" id="myButton" value="button" onClick="alert('Hello')"/>
That is, of course, ridiculously convoluted and "hacky" code to achieve something as simple as disabling a button.
My questions
- Why is it that jQuery - unlike vanilla JS - doesn't disable the events when disabling a button?
- Is this to be considered a bug or a feature in jQuery?
- Is there something I'm overlooking?
- Is there a simpler way to get the expected behavior in jQuery?