سؤال

I have a directive disable-ng-clicks and under certain conditions, I want to prevent all ng-clicks that are children of the directive. Here is some example markup:

<div disable-ng-clicks> <!-- directive -->
  <a ng-click="someAction()"></a>
  <div ng-controller="myController">
    <a ng-click="anotherAction()"></a>
    <a ng-click="moreActions()"></a>
  </div>
</div>

If these were normal hyperlinks, I could do something like this in the link function:

function(scope, iElement, iAttrs) {
  var ngClicks = angular.element(iElement[0].querySelectorAll('[ng-click]'));
  ngClicks.on('click', function(event) {
    if(trigger) { // a dynamic variable that triggers disabling the clicks
      event.preventDefault();
    }
  });
}

But this does not work for ng-click directives. Is there another way to accomplish this?

هل كانت مفيدة؟

المحلول

Here is the best I could come up with. I created a new directive to replace ng-click:

 directive('myClick', ['$parse', function($parse) {
  return {
    restrict: 'A',
    compile: function($element, attrs) {
      var fn = $parse(attrs.myClick);
      return function (scope, element, attrs) {
        var disabled = false;
        scope.$on('disableClickEvents', function () {
          disabled = true;
        });
        scope.$on('enableClickEvents', function () {
          disabled = false;
        });
        element.on('click', function (event) {
          if (!disabled) {
            scope.$apply(function () {
              fn(scope, { $event: event });
            });
          }
        });
      };
    }
  }
}]);

So in a different directive, I can have:

if (condition) { 
  scope.$broadcast('disableClickEvents');
}

and when I want to re-enable:

if (otherCondition) { 
  scope.$broadcast('enableClickEvents');
}

I don't like having to use a different directive for ng-click, but this is the best plan I could think of.

نصائح أخرى

You are catching 'click' event on parent only because of JS events bubbling, so if you want to intercept it on all descendants, so your directive should get all descendants of current element, listen their 'click' event and prevent it if necessary.

This directive will iterate over all child elements, check to see if they have an ng-click attribute, and if they do, it will disable any registered click event handlers:

directive('disableNgClicks', function(){
  return {
    restrict: 'E',
    link: function(scope, elem, attrs){
      angular.forEach(elem.children(), function(childElem) {
        if (childElem.outerHTML.indexOf("ng-click") > -1) {
          angular.element(childElem).off('click');
        }
      });
    }
  }
})

Plunker demo

I know this is 2 years ago but I needed to do something similar and came up with a rather simple solution.

The object:

items: {
    item1 : {
        selected: 0,
        other: 'stuff'
    },
    item2 : {
        selected : 1,
        other: 'stuff'
    }  
}

The HTML:

<div ng-repeat="item in items" ng-model="item.selected" ng-click="selectParent($event)">
    <div ng-click="item.selected ? selectChild($event) : null">Child</div>
</div>

The functions:

$scope.selectParent = function($event) {
    var itemScope = angular.element($event.currentTarget)scope().item;
    itemScope.selected = !itemScope.selected;
}

$scope.selectChild = function($event) {
    $event.stopPropagation;
    console.log('I only get triggered if parent item is selected');
}

This is a pretty raw example of what I did. You should probably be using a directive that gives you $scope rather than angular.element($event.currentTarget).scope... either way the simplistic inline if logic is what I was really getting at. You can call a function or not based on some value.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top