5

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)?

7
  • why you used private function in your angular controller? Commented Jun 29, 2016 at 4:21
  • @Maher I have this.doubleClickHandler = doubleClickHandler; in my controller, but that is besides the point I think? Commented Jun 29, 2016 at 4: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. Commented Jun 29, 2016 at 4: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. Commented Jun 29, 2016 at 4:27
  • are you using jquery along with angular? Commented Jun 29, 2016 at 4:29

5 Answers 5

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
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks. This is exactly what I am looking for. Also, stackoverflow.com/questions/10086427/… is helpful.
great :), simple as that
Yeah, this is not actually an Angular-specific answer. In Angular, if you also want to handle events from inner non-button elements like <span>, you can check if event.target has attributes like [ng-click].
You saved my life with that currentTarget, thx
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?

1 Comment

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.
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

1 Comment

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.
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>

2 Comments

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.
thanks for the new answer, but it is an overkill, the answer that I accepted is way simpler.
0

You can also do it in-line this way (tested & proved):

<div (click)="$event.target==$event.currentTarget ? yourFunctionHere():null">

$event.target==$event.currentTarget checks whether to run yourFunctionHere() or not (being null here, if you like you could replace it with another function too).


event.target is "The associated EventTarget."

event.currentTarget is "An EventTarget representing the object to which the current event handler is attached."

Essentially what you are doing is checking whether your current action matches that of the current elements triggered action. If they're the same, then we run your code, if not we run null (which does nothing).

Comments

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.