user2723490
user2723490

Reputation: 2100

How to trigger a click event on disabled elements

I have a disabled button, which is enabled after checking "I accept terms and conditions" checkbox. The problem is that I wanted to trigger an alert, if a user clicks the disabled button. How can I do this? If an element is disabled, it looks as "onclick" events are not fired.

The sample of the code:

<input id="subm_tc" class="btn btn-primary" type="submit" disabled="" value="Log in" name="Submit">

    $("#subm_tc").click(function () {
        if($("#modlgn-tc").is(':checked')){
            alert('checked');
        } else {
            alert('unchecked');
        }
    });

If I wrap the element in div and listen to clicks on that div, it works, but you need to click outside the button.

How can I fix this?

Thanks

UPDATE. I've managed to resolve this by adding a fake div over the submit button and listening to events on that div (I also change z-index to -200 to enable clicks on the button itself):

<div style="position:relative">
<div id="subm_tc" style="position: absolute; left: 0px; right: 0px; bottom: 0px; top: 0px; z-index: 99999;"></div>
<input id="subm_tc" class="btn btn-primary" type="submit" disabled="" value="Log in" name="Submit">
</div>

Now it works as intended

Upvotes: 26

Views: 58339

Answers (7)

chiliNUT
chiliNUT

Reputation: 19573

My solution was to put the button in a div, which is clickable. when the button is disabled, the div has the width and height of the button, so clicking the button triggers the div. when the button is enabled, the div is shrunk to 0 width 0 height, so the click event registers with the button instead of the div. This code includes some demoing code as well for a toggle button which toggles the enabled/disabled state of the button in question

fiddle: http://jsfiddle.net/6as8b/2/

HTML

$(document).ready(function() {
  $('#clickable').on('click', function() {
    if ($('#theButton:disabled').length > 0) {
      $('#clicks').append('|Disabled Button Clicked|<br>');
    } else {
      //do nothing and let the button handler do it
      $('#theButton').click();
    }
  });
  $('#theButton').on('click', function() {
    $('#clicks').append('|ENABLED button clicked|<br>');
  });
  $('#toggle').on('click', function() {
    if ($('#theButton:disabled').length > 0) {
      $('#theButton').removeAttr('disabled');
      $('#clickable').css({
        'width': '0px',
        'height': '0px'
      });
    } else {
      $('#theButton').attr('disabled', 'disabled');
      $('#clickable').css({
        'width': '55px',
        'height': '25px'
      });
    }
  });
});
#clickable {
  position: absolute;
  width: 55px;
  height: 25px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
Click 'Toggle" to make 'Button' enabled or disabled. click it, and see that that one event fires if it is enabled, and another if disabled.
<br />
<input type=button value='toggle' id='toggle'>
<br /><br />
<div style='position:relative'>
  <div id='clickable'></div>
  <input id=theButton type=button disabled value='Button'>
</div>
<div id=clicks></div>

Upvotes: 13

raiku
raiku

Reputation: 105

While the solutions provided here are fine and get the job done, they shouldn't be used lightly since there are accessibility issues that come with them.

Another way that also respects accessibility would be to ditch the disabled attribute, add an aria-disabled="true" for screenreaders and styling for the disabled button/input:

<input 
    id="subm_tc" 
    class="btn btn-primary" 
    type="submit" 
    aria-disabled="true" 
    value="Log in" 
    name="Submit"
>
$("#subm_tc").click(function () {
    if ($("#subm-tc").getAttribute("aria-disabled") === "true") {
        alert("This button is disabled");
        return;
    }

    if ($("#modlgn-tc").is(':checked')){
        alert('checked');
    } else {
        alert('unchecked');
    }
});
input[aria-disabled="true"] {
    cursor: not-allowed;
    background-color: gray;
    color: white;
}

Needless to say but this could also be achieved without jQuery.

Upvotes: 1

SKisby
SKisby

Reputation: 65

2022 Update: I know this is an old question, but here's an update after evaluating various solutions, including CSS position:absolute and pointer-events:none

The disadvantage of simulating the disabled look ("Pretend Disable") was that, back then, various browsers presented disabled elements differently. That's not as true today because Chrome, Edge, Firefox, and other modern browsers, implement disabled button inputs (and likely other inputs) with the equivalent of opacity .5 .

The solution below is inspired by https://css-tricks.com/making-disabled-buttons-more-inclusive which uses the aria-disabled attribute in place of the older disabled attribute. That article strongly advised against using CSS techniques such as position:absolute and pointer-events:none, because when disabled, the input (or underlying/overlying element) cannot receive focus preventing the possibility of an automatic tooltip when tabbed to and preventing a screen reader from announcing the element is disabled.

Accessible Rich Internet Applications (ARIA) is a set of attributes that define ways to make web content and web applications (especially those developed with JavaScript) more accessible to people with disabilities.

HTML:

<input type='button' id='toggle' value='Toggle'>
<input type='button' id='theButton' value='Button'>
<div id='clicksReport'></div>

Plain JavaScript:

document.querySelector('#theButton').onclick = function () {
    if (document.querySelector('#theButton').ariaDisabled)
    {
        // Your disabled button code (if any)
        document.querySelector('#clicksReport').insertAdjacentHTML("beforeend",'|Disabled Button Clicked|<br>');
    }
        else
    {
        // Your emabled button code
        document.querySelector('#clicksReport').insertAdjacentHTML("beforeend",'|ENABLED button clicked|<br>');
    }
}

document.querySelector('#toggle').onclick = function() {
   if (document.querySelector('#theButton').ariaDisabled)
    {
        // If not a button input, also remove the readOnly attribute
        var el = document.querySelector('#theButton');
        el.ariaDisabled = null;
        el.style.opacity = null;
    }
        else
    {
        // If not a button input, also set the readOnly attribute
        var el = document.querySelector('#theButton');
        el.ariaDisabled = true;
        el.style.opacity = '.5';
    }
}

JS Fiddle: https://jsfiddle.net/SKisby/3Lna8q7h/7/

The same in d3 (as that's what I'm currenlty using and it's similar to jQuery):

d3.select('#theButton').on('click',function () {
    if (d3.select('#theButton').attr('aria-disabled'))
    {
        // Your disabled button code (if any)
        d3.select('#clicksReport').node().insertAdjacentHTML("beforeend",'|Disabled Button Clicked|<br>');
    }
        else
    {
        // Your emabled button code
        d3.select('#clicksReport').node().insertAdjacentHTML("beforeend",'|ENABLED button clicked|<br>');
    }
});

d3.select('#toggle').on('click',function() {
   if (d3.select('#theButton').attr('aria-disabled'))
    {
        // If not a button input, also remove the readOnly attribute
        d3.select('#theButton').attr('aria-disabled',null)
        .style('opacity',null);
    }
        else
    {
        // If not a button input, also set the readOnly attribute
        d3.select('#theButton').attr('aria-disabled',true)
        .style('opacity','.5');
    }
});

d3 Fiddle: https://jsfiddle.net/SKisby/qkvf3opL/2/

The above are simple, both have the same disabled look in Chrome, Firefox, and other modern browsers, and have the benefits of being able to receive focus (where an automatic tooltip could then be implemented and ARIA screen readers can convey the element is effectively disabled).

If the input is not a button, also set and remove the readOnly attribute.

Upvotes: 3

Oliver
Oliver

Reputation: 547

Old topic, but here are my two cents as I had the same challenge lately:

Don't try to position a clickable element above it but wrap it with one so you won’t directly be able to click it. Assuming a button with display: inline-block set:

<span class="on-disabled">
  <input id="subm_tc" class="btn btn-primary" type="submit" disabled value="Log in" name="Submit">
</span>

Define you click event for the case of the button being disabled:

$('.on-disabled').click(function (ev) {
  // Don’t react to click events bubbling up
  if (ev.target !== ev.currentTarget) return;
  // Do your thing
  alert('Sorry, this button is disabled');
});

And simply style the button like:

#subm_tc {
  display: inline-block;
}

#subm_tc[disabled] {
  position: relative;
  z-index: -1;
}

This allows you to easily react to a click even in case of a disabled button. See FIDDLE.

Upvotes: 1

james
james

Reputation: 4049

If you use Twitter Bootstrap, they give you a class disabled that provides the styling but doesn't remove the click event. Given that, what I did was this (keep in mind also, I wanted to be sure that when the button was no longer disabled, the original click event did fire, and I didn't want to deal with unbinding, rebinding it).

function disableButton(btn, message) {
  btn.addClass("disabled")
  if (!(message == null || message == "")) {
    btn.data("message", message)
  }
}

function enableButton(btn) {
  btn.removeClass("disabled")
}

$("#btn").click(function() {
  if (!($(this).hasClass("disabled"))) {
    // original, desired action
  } else {
    message = $(this).data("message")
    if (!(message == null || message == "")) {
      alert(message)
    }
  }

})

Upvotes: 0

Paul S.
Paul S.

Reputation: 66304

You can write a function that adds listeners to the mousedown and mouseup events, and if the targets match your Node (i.e. the mousedown and following mouseup were on your element), then it invokes another function

function listenFullClick(elm, fn) {
    var last;
    document.addEventListener('mousedown', function (e) {
        last = e.target === elm;
    });
    document.addEventListener('mouseup', function (e) {
        if (e.target === elm && last) fn();
    });
};

listenFullClick(
    document.getElementById('foo'), // node to look for
    function () {alert('bar');}     // function to invoke
);

DEMO

Upvotes: 3

adeneo
adeneo

Reputation: 318172

Disabled elements doesn't trigger any mouse events at all, so that's probably a lost cause.

However, when clicking a parent element, the event.target seems to be given correctly, which means this should work :

$(document).on('click', function (e) {   
    if (e.target.id == 'subm_tc') {
        if($("#modlgn-tc").is(':checked')){
             alert('checked');
        } else {
             alert('unchecked');
        }
    }
});

FIDDLE

Upvotes: 3

Related Questions