3

I know this can be done with jQuery as shown here: How to have click event ONLY fire on parent DIV, not children?

$('.foobar').on('click', function(e) {
  if (e.target !== this)
    return;

  alert( 'clicked the foobar' );
});

But in angular, this keyword is not binded to the element when I use something like:

<div ng-dblclick="ctrl.doubleClickHandler($event)">
    parent, event should fire here.
    <div>child, event should not fire here.</div>
</div>

and in my controller:

this.doubleClickHandler = doubleClickHandler;
function doubleClickHandler(event) {
  console.log(this); // this binds to controller
  console.log(event);
}

The event fires, but I need to prevent it from firing when I click on the element's children.

I don't want to hardcode a check on the event.target based on class or attribute because it might change later. Is there anyway to achieve this within the HTML tag, or in JavaScript without hardcoding the element's class or attributes (similar to the technique of binding the this keyword in jQuery)?

Community
  • 1
  • 1
paradite
  • 6,238
  • 3
  • 40
  • 58
  • why you used private function in your angular controller? – Maher Jun 29 '16 at 04:21
  • @Maher I have `this.doubleClickHandler = doubleClickHandler;` in my controller, but that is besides the point I think? – paradite Jun 29 '16 at 04:23
  • @Maher I've been taught to keep any controller logic that does not need to be tied to $scope private within the controller via this.ctrlFunc() rather than $scope.cntrlFunc(). It is still public in that you can call the function within the controller via the name you assign the controller. – alex bennett Jun 29 '16 at 04:24
  • i know that, we can define scopes as anything in controller, but in this sample we define the function as private, so we can't get the console. – Maher Jun 29 '16 at 04:27
  • are you using `jquery` along with `angular`? – Kalhan.Toress Jun 29 '16 at 04:29
  • @K.Toress yes, I can use jQuery if necessary. – paradite Jun 29 '16 at 04:30
  • Possibly related question [AngularJS - get element attributes values](http://stackoverflow.com/q/24673418/4519059) ;). – shA.t Jun 29 '16 at 04:45

4 Answers4

14

You can compare target and currentTarget. The former is the clicked element and the latter is the element with the handler.

function doubleClickHandler(event) {
  if (event.target !== event.currentTarget) return;
  // do something
}
Shuhei Kagawa
  • 4,752
  • 1
  • 33
  • 31
  • 1
    Thanks. This is exactly what I am looking for. Also, http://stackoverflow.com/questions/10086427/what-is-the-exact-difference-between-currenttarget-property-and-target-property is helpful. – paradite Jun 29 '16 at 04:55
  • great :), simple as that – Kalhan.Toress Jun 29 '16 at 04:59
  • 1
    Yeah, this is not actually an Angular-specific answer. In Angular, if you also want to handle events from inner non-button elements like ``, you can check if `event.target` has attributes like `[ng-click]`. – Shuhei Kagawa Jun 29 '16 at 05:05
  • You saved my life with that currentTarget, thx – manudicri Jun 24 '21 at 14:53
0

I think you could try something like this:

<div ng-dblclick="ctrl.doubleClickHandler($event) $event.stopPropagation()">

reference: What's the best way to cancel event propagation between nested ng-click calls?

Community
  • 1
  • 1
alex bennett
  • 794
  • 1
  • 10
  • 17
  • 2
    This does not work. I think it's because the children has that exact same event listener, just firing with different `event.target`. So event fires anyway. – paradite Jun 29 '16 at 04:26
0

i update the answer by create directive with jquery in your sample.

var app = angular.module("app", []);

        app.controller("controller", function ($scope) {
            var ctrl = this;


            ctrl.doubleClickHandler = function () {
                alert("parent clicked")
            }
        });


        app.directive("directiveName", function () {
            return {
                restrict: "A",
                scope: {
                    click: "&"
                },
                link: function (scope, element, attr) {

                    element.on('click', function (e) {
                        if (e.target !== this) {
                            return;
                        } else {
                            scope.click()
                        }
                    });

                }
            }
        })
.foobar span {
            background: red;
        }
<!DOCTYPE html>
<html ng-app="app" ng-controller="controller as ctrl">
<head>
    <title></title>
</head>
<body>
    <div click="ctrl.doubleClickHandler()" directive-name class="foobar">

        parent

        <span>
            child
        </span>

    </div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

</body>
</html>
Maher
  • 2,517
  • 1
  • 19
  • 32
  • Hi, you misunderstood my question, the event is firing, but I need to only fire on the element with `ng-dbclick`, but not its children. – paradite Jun 29 '16 at 04:30
  • thanks for the new answer, but it is an overkill, the answer that I accepted is way simpler. – paradite Jun 29 '16 at 04:57
0

If your using jquery try this,

<div class="foobar"> .foobar (alert)
      <span>child (no alert)</span>
</div>

$('.foobar').on('click', function(e) {
    if (e.target !== this)
      return;

    $scope.myFunc(e);
});


$scope.myFunc = function(e) {
     $scope.clicked = "Parent Cicked";
    $scope.$apply();
};

DEMO

surely its not leading to a good programmatic skills. Hence you can try below example with angular and JS

<div class="foobar" data-parent="true" ng-click="myFunc($event)"> .foobar (alert)
      <span>child (no alert)</span>
</div>

// add data attribute as data-parent="true"

$scope.myFunc = function(e) {
    if (! e.target.hasAttribute('data-parent'))
        return;

    $scope.clicked = "Parent Cicked";
};

//if clicked element has `data-parent` property do the things.

DEMO

Kalhan.Toress
  • 21,683
  • 8
  • 68
  • 92
  • Thanks for the answer, but I would prefer not to check on attributes or classes(see description of question). Otherwise it defeats the purposes of adding `ng-click` on that particular element, since I could just add it on `body` and achieve the same effect. – paradite Jun 29 '16 at 04:51