0

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?

Rohit
  • 3,018
  • 2
  • 29
  • 58
  • 3
    I don't and haven't used angular but maybe this post could help you? [**How to ignore click event when clicked on children**](https://stackoverflow.com/questions/3864102/how-to-ignore-click-event-when-clicked-on-children) so maybe a second function or adding `stopPropagation();` will work? Just a shot in the dark since I don't use Angular. – NewToJS Oct 20 '17 at 03:10

2 Answers2

1

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>
Bilal Djaghout
  • 166
  • 3
  • 14
  • 1
    I considered `stopPropogation`, but couldn't quite think about how to do it. I guess I could create a click on the child and stop propogation on it. – Rohit Oct 20 '17 at 03:37
  • @RhoVisions That should work, so I guess my suggestion would be the right path to take? Reason I'm asking is because I plan to start using Angular very soon so remembering this might be useful to me at some point. – NewToJS Oct 20 '17 at 03:40
  • Mate this is AngularJs I suggest working with Angular 4 instead – Bilal Djaghout Oct 20 '17 at 03:41
  • Yah, I didn't comment on the Angular version as it wasn't relevant to question, but my code above is Angular, as is the tag of the question. I actually came up with a more Angular-based question that doesn't rely on multiple click events; I'll post it shortly. – Rohit Oct 20 '17 at 03:45
1

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.

greduan
  • 4,770
  • 6
  • 45
  • 73
Rohit
  • 3,018
  • 2
  • 29
  • 58