Rohit
Rohit

Reputation: 3146

Ignoring click event when child of element is clicked

I may just be thinking about this wrong because I'm doing it in Angular and over complicating, but what I'm trying to do is setup my click event so it only triggers when an element is clicked, but not it's child. I'm trying to setup a modal, where if you click the background overlay it closes, but obviously I don't want it closing if the user interacts with the modal.

<div class="overlay">
    <div class="modal">
    </div>
</div>

So far, I've created this:

@HostListener('document:click', ['$event.target']) public onClick(targetElement: HTMLElement) {
    const clickedInside = this._elementRef.nativeElement.contains(targetElement);
    if (!clickedInside && targetElement.class.indexOf('overlay') && targetElement.parentElement.tagName === 'GP-MODAL') {
        //do stuff
    }
}

Where _elementRef is the Angular ElementRef. The problem is it feels like an inefficient way of doing it: trigger on any click, only continue on certain elements. It feels more ideal to trigger a click on .overlay and then somehow not have it go off in .wrapper, but I can't think of how to do it. Any advice?

Upvotes: 1

Views: 2163

Answers (2)

Rohit
Rohit

Reputation: 3146

I came up with two possible methods, depending on selection criteria.

The first is just Javascript: If you know a specific attribute of the clicked element you can check on, create a click event on the element you want to track, bound to:

clickedOverlay(event) {
    if (event.target.parentElement.tagName === 'GP-MODAL') {
        // Do stuff
    }
}

A more Angular focused answer:

@ViewChild('target') targetRef: ElementRef;

clickedOverlay(event: MouseEvent) {
    if (this.targetRef.nativeElement === event.target) {
        // Do stuff
    }
}

It's more explicit, and less prone to false positives, but more verbose.

Not suggesting these are the best answers, but my preference right now.

Upvotes: 1

Bilal Djaghout
Bilal Djaghout

Reputation: 176

I think what you are looking for is the stopPropagation method, which resides in the event object

(function () {
  var app = angular.module('app', []);
  app.controller('MainCtrl', MainController);
  
  MainController.$inject = [];
  
  function MainController () {
    var vm = this;
    vm.onClick = function (event) {
      event.stopPropagation();
      alert('Child clicked');
    };
    
    vm.parentOnClick = function (event) {
      alert('Parent clicked');
    };    
  }
  
}) ();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>
<body ng-app="app" ng-controller="MainCtrl as vm">
  <div ng-click="vm.parentOnClick($event)" style="height: 400px; width: 400px; background: red;">
    <div ng-click="vm.onClick($event)" style="position: absolute; top: 100px; left: 100px; background: blue; height: 200px; width: 200px;">
    </div>
  </div>
</body>

Upvotes: 2

Related Questions