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

2
  • 2
    If you don't use the built in ng-disabled, you would probably not want to use the built-in ng-click either. Commented Apr 29, 2014 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). Commented Apr 29, 2014 at 14:18

4 Answers 4

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! One question: Is event.preventDefault(); really required here?
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).
capturing phase is not supported on IE, so it will not be cross-browser
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.

Comments

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

Comments

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?

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.