4

LIVE DEMO

Consider the following myButton directive:

angular.module("Demo", []).directive("myButton", function() {
  return {
    restrict : "E",
    replace: true,
    scope: {
      disabled: "="
    },
    transclude: true,
    template: "<div class='my-button' ng-class='{ \"my-button-disabled\": disabled }' ng-transclude></div>",
  };
});

which can be used like this:

<my-button disabled="buttonIsDisabled" 
           ng-click="showSomething = !showSomething">
  Toggle Something
</my-button>

How could I stop ng-click from executing when buttonIsDisabled is true?

PLAYGROUND HERE

Misha Moroshko
  • 166,356
  • 226
  • 505
  • 746
  • 2
    If you don't use the built in `ng-disabled`, you would probably not want to use the built-in `ng-click` either. – lyschoening Apr 29 '14 at 13:35
  • 2
    Actually, neither `disabled` nor `ngDisabled` (which is backed by `disabled`) will have any effect here, since they are placed on a `div` (not an `input` or a `button`). – gkalpak Apr 29 '14 at 14:18

4 Answers4

5

You could use capture (addEventListener's optional third parameter) and stop the propagation of the event (using stopPropagation).

"Capture" allows you to catch the event before it reaches the "bubble" phase (when the triggering of "normal" event-listeners happens) and "stopPropagation" will...stop the propagation of the event (so it never reaches the bubbling phase).

element[0].addEventListener('click', function (evt) {
    if (scope.disabled) {
        console.log('Stopped ng-click here');
        evt.preventDefault();
        evt.stopPropagation();
    }
}, true);

See, also, this short demo.

Chris Barr
  • 29,851
  • 23
  • 95
  • 135
gkalpak
  • 47,844
  • 8
  • 105
  • 118
  • Thanks! One question: Is `event.preventDefault();` really required here? – Misha Moroshko Apr 29 '14 at 23:32
  • You got me :) It seems to work just as good without it, but 1.) it doesn't hurt and 2.) I felt it makes the code more declarative (i.e. it makes it easier to understand that the purpose of that block it to cancel the event). – gkalpak Apr 30 '14 at 07:10
  • capturing phase is not supported on IE, so it will not be cross-browser – Armen May 06 '14 at 08:45
2

Why not use the actual button for your button. You could change your directive to:

angular.module("Demo", []).directive("myButton", function() {
  return {
    restrict : "E",
    replace: true,
    scope: {
      disabled: "="
    },
    transclude: true,
    template: "<button class='my-button' ng-class='{ \"my-button-disabled\": disabled }' ng-disabled='disabled' type='button' ng-transclude></button>"
  };
});

Then style it to look like your div. See the Short Example I've made.

lpiepiora
  • 13,659
  • 1
  • 35
  • 47
1

Try this in your link function:

link: function(scope, element, attrs) {
      var clickHandlers = $._data(element[0]).events.click;

      clickHandlers.reverse(); //reverse the click event handlers list

      element.on('click', function(event) {
        if (scope.disabled) {
          event.stopImmediatePropagation(); //use stopImmediatePropagation() instead of stopPropagation()
        }
      });

      clickHandlers.reverse(); //reverse the list again to make our function at the head of the list
}

DEMO

This solution uses jQuery to deal with cross browser problems. The idea here is to attach our event handler at the head of the click handlers list and use stopImmediatePropagation() to stop current handlers of the same event and bubbling event.

Also take a look at this: jquery: stopPropagation vs stopImmediatePropagation

Community
  • 1
  • 1
Khanh TO
  • 48,509
  • 13
  • 99
  • 115
0
<my-button disabled="buttonIsDisabled" 
       ng-click="showSomething = buttonIsDisabled ? showSomething : !showSomething">

or

<my-button disabled="buttonIsDisabled" 
       ng-click="showSomething = buttonIsDisabled ? function(){} : !showSomething">

Is this too simple?

Chi Row
  • 1,106
  • 7
  • 18
  • 1
    as I understand, the question asks about stopping ng-click `in a directive` so that we don't need to care about adding this logic everywhere that is using this directive. – Khanh TO Apr 29 '14 at 15:03