Angular 4+ Detect click in Div or nested child Divs and distinguish from other outside Divs

Yogi Bear Source

I have seen many Angular 2 pages that loop through a hierarchy of nativeElements. They don't work in Angular 4, 5, ... I need to add a directive to a "workspace" DIV. There will be other Divs that are parent of workspace and others are child DIVs nested to any level. This directive must detect a mouse click for the "workspace" div OR any of the nested divs and I must determine that it is in fact a nest child or the workspace -- and NOT some other div above workspace or outside workspace.

This is derived from one of the many examples on the web:

    import {Directive, ElementRef, HostListener} from '@angular/core';

@Directive({
  selector: '[shMonitorInfoClicks]'
})
export class MonitorInfoClicksDirective {
  public elementRef;

  constructor(private myElement: ElementRef) {
    this.elementRef = myElement;
  }

  @HostListener('document:click', ['$event'])
  public onClick(event: Event): void {
    let clickedComponent = event.target;
    let inside = false;
    do {
      if (clickedComponent === this.elementRef.nativeElement) {
        inside = true;
        break;
      } else {
        clickedComponent = clickedComponent.parentNode;  <<<<====== see below
      }
    } while (clickedComponent);
    if(inside) {
      console.log('inside');
    } else {
      console.log('outside');
    }
  }
}

The test HTML:

<div>
  This is outside the workspace
</div>
<div shMonitorInfoClicks  [ngStyle]="{'height': '200px', 'width': '300px', 'border': '1px solid red'}">
  This is the workspace
  <div [ngStyle]="{'height': '100px', 'width': '100px', 'border': '1px solid green'}">
    A workspace child
  </div>
</div>

When I pause in the Chrome debugger, I am able to use the console to make parentNode or parentElement work. However, I can't get past Typescript/Angular CLI. I made sure I'm running the @latest Angular. (It's 5).

Any help will be appreciated. Thanks in advance.

angularelementref

Answers

answered 3 months ago vincecampanale #1

The event.target.parentNode reference doesn't get past the compiler because the compiler is viewing event.target as an EventTarget, which doesn't have a parentNode property. In order to inform the compiler what your event.target really is, you need to use a type assertion to cast the event.target it's real type, which in your case is an HTMLElement:

const target = event.target as HTMLElement;

Now you will have access to target.parentNode.

The reason you are able to see it in the console is because that is printing out the event.target at runtime (types not included), but Angular's event object's target property returns something else. You can see a little more information here: https://angular.io/guide/user-input#type-the-event, but it's hard to find more information on it.

Anyways, you can always use the console to figure out what the type of your event.target really is and then cast your event.target to that type in the code. Then you can access all those properties you see in the console without the compiler throwing a fit :)

comments powered by Disqus