Prevent onclick action with jQuery

75,629

Solution 1

jQuery is not going to solve this one OOTB. It can help, but none of stopPropagation, stopImmediatePropagation, preventDefault, return false will work if you simply attach them to the element. You need to override the element's click handler.

However you state in your question "without removing onclick actions". So you need to override the default behavior at the point the event is triggered, (as opposed to the cleaner approach of simply nulling out the onclick attribute for disabled anchors):

Here's what I mean:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<title>Disable clicks</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
</head>
<body>
  <a href="#" onclick="alert('panic!')">Let's panic</a>
  <a href="#" onclick="alert('panic!')" disabled="disabled">I can't panic no more</a>

  <script>
  $('a[onclick]').each(function(){
    $(this).data('onclick', this.onclick);

    this.onclick = function(event) {
      if($(this).attr('disabled')) { // HERE
        return false;
      };

      $(this).data('onclick').call(this, event || window.event);
    };
  });
  </script>
</body>
</html>

Demo here.

The approach there is to override the inline click handler (onclick) with preemptive logic to catch the case where the anchor is "disabled" and then cancel the event (with return false).

The benefit there is that to enable an anchor again you simply .removeAttr('disabled') on it.

Solution 2

disabled isn't a property of anchors. Use something like rel='disabled' instead.

$('a[rel="disabled"]').click( function() { return false; } );

Update:

Ah, of course. It still fires the alert because it's actually inline in the markup! I never do that and so didn't notice. Take that click handler out of the markup and do it in jQuery in the first place and so you can then just do something like:

$('a').click( function() {
  if( $(this).attr('rel') == 'disabled' ) { return; }
  // do stuff here when not disabled
  return false; // so your '#' href doesn't get used
} );

Solution 3

The problem is that jQuery adds events in order. To stop other events, the events you need to stop must come after your stopping code. Since you have code in your on click, you will need to change up the order. This is what I would do:

<a href='#' onclick="alert('HA-ha!')" class="disabled">TEST</a>
<a href='#' onclick="alert('HA-ha!')">TEST</a>
<script type="text/javascript">
    $('a').each(function(){
        // Cache event
        var existing_event = this.onclick;

        // Remove the event from the link
        this.onclick = null;

        // Add a check in for the class disabled
        $(this).click(function(e){ 
            if($(this).hasClass('disabled')){
                e.stopImmediatePropagation();
                e.preventDefault();
            }                
        });

        // Reattach your original onclick, but now in the correct order
        // if it was set in the first place
        if(existing_event) $(this).click(existing_event);
    });
</script>

The benefit is just remove/add the disabled class using jQuery: $('a#whatever').addClass('disabled') or remove it $('a#whatever').removeClass('disabled') and no other cleanup/setup is required.

Solution 4

Any click handlers added by jQuery seem to fire after those added in the mark up. My solution would be to apply the click handlers using jQuery instead of in the mark up, but you may not have enough control over the code to do this. If you do, then simply don't apply the click handler to anchor tags with class disabled (and, yes, I would use a class rather than an inappropriate attribute). If you don't have control over the mark up, then you might want to replace the click handler using jQuery, storing it for later reapplication.

   $(function() {
      $('a.disabled').each( function() {
         var $this = $(this);
         var click = $this.attr('onclick');
         if (click) {
             $this.data('click',click);
             // add return false to prevent default action
             $this[0].onclick =  function() { return false; };
         }
      });

      $('#restoreClick').click( function() {
          $('a.disabled').each( function() {
              var $this = $(this);
              $this.removeClass('disabled');
              var click = $this.data('click');
              if (click) {
                  $this[0].onclick = click;
              }
          });
      });
   });

Tested with:

<div>
    <a href="#" onclick="alert('panic!')">Let's panic</a>
    <a href="#" onclick="alert('panic!')" class="disabled">I can't panic no more</a>
</div>
<div>
    <input type="button" id="restoreClick" value="Restore" />
</div>
Share:
75,629
Andrew Rumm
Author by

Andrew Rumm

Fullstack-developer.

Updated on October 03, 2020

Comments

  • Andrew Rumm
    Andrew Rumm over 3 years

    there are some links with onclick event actions

    <a href="#" onclick="alert('panic!')">Let's panic</a>
    <a href="#" onclick="alert('panic!')" disabled="disabled">I can't panic no more</a>
    

    I need prevent event actons execution on links with disabled attribute without removing onclick actions.

    $('a[disabled]').click(function(e){
      e.stopPropagation();
      return false;
    });
    

    This code doesn't helps me.

    update Even this code doesn't work

    <html><head><script type='text/javascript' src='jquery-1.3.2.js'></script></head>
    <body>
    <a href='#' onclick="alert('HA-ha!')" disabled="disabled" class="disabled">TEST</a>
    <script type="text/javascript">
        $('a[disabled], a.disabled').click(function(e){
            console.log('override?');
            e.stopImmediatePropagation();           
                e.preventDefault();
            e.stopPropagation();
            return false;       
        });
    </script>
    </body></html>
    
    • Hooray Im Helping
      Hooray Im Helping over 14 years
      return false; vs. e.preventDefault(); vs e.stopPropagation(); discussion found here: stackoverflow.com/questions/1357118/…
    • rfunduk
      rfunduk over 14 years
      All of your jQuery code should be wrapped in a $(document).ready( function() { ...code here... } ); That, in combination with removing the disabled tag from your markup and selector should get things working.
  • rfunduk
    rfunduk over 14 years
    Yea, jQuery should be able to make a[disabled="disabled"] work, but IMO that's a bad idea. Stick with valid markup :)
  • Andrew Rumm
    Andrew Rumm over 14 years
    anyway, i've got tryed to prevent using some class named disabled. It still does nothing.
  • Doug Neiner
    Doug Neiner over 14 years
    Nice clean solution! Is the event || window.event necessary since jQuery already normalizes the browsers and the event object is the cleaned up version by the time your code calls it?
  • Crescent Fresh
    Crescent Fresh over 14 years
    @dcneiner: yeah, it's required. Notice we're just in an inline event handler (onclick) that the browser invokes, not a handler jQuery normalizes and invokes.
  • Andrew Rumm
    Andrew Rumm over 14 years
    Great! Thank you for solve and explanation. Exactly what i need.
  • dgo
    dgo over 10 years
    I'm not a huge fan of using "javascript:", but this was by far the simplest solution to the problem. You prefer the other client side scripting languages do ya?
  • MrBojangles
    MrBojangles over 10 years
    I love JavaScript, but I prefer not to use javascript inline with the "javascript:" syntax. "javascript:alert('panic!')" <-- example. The first requirement of a smart-ass remark is that it be "smart" ;)
  • jasiustasiu
    jasiustasiu about 10 years
    I used eval(event.currentTarget.getAttribute('onclick')); instead of $(this).data('onclick').call(this, event || window.event);. Both solutions work. Thanks!