7

I couldn't find this anywhere in the docs, but my Node.contains() function is not working when I click something inside a component that is part of a parent component.

My parent component looks like this:

<div class="body">
    <div class="item" *ngFor="let item of sortedItems;">
        <cv-checkbox></cv-checkbox>
        <cv-svg-icon></cv-svg-icon>
    </div>

    <div class="drop-zones" *ngFor="let zone of sortedItems.length + 1 | numberToArrayPipe;>
        <div class="drop-zone"></div>
    </div>
</div>

As you can see i have two Angular components inside my parent component: cv-checkbox and cv-svg-icon. I've added a directive to my parent component that looks like this:

<cv-layer-manager cvClickOutside (clickOutside)="toggleLayerManager()"></cv-layer-manager>

Where i check if the clicked Node is contained by the parent like this:

@HostListener('document:click', ['$event']) public onClick(event: MouseEvent) {
    const clickedInside = this._elementRef.nativeElement.contains(event.target);
    if (!clickedInside) {
        this.clickOutside.emit();
    }
}

If i click normal HTML components everything works as expected but not when i'm clicking on an Angular component. Is it correct that contains doesn't check inside the Angular component?

Martijn van den Bergh
  • 1,434
  • 1
  • 20
  • 40

2 Answers2

6

I had a similar issue with a datepicker. To fix this problem I added allowClose property to current component.

@ViewChild('element') elementRef: ElementRef;
private allowClose = true;

Then I added another HostListener that listens only to events of current component.

@HostListener('click', ['$event'])
clickInside(event: any) {
  this.allowClose = false;
}

Then I modified my clickOutside method to handle close only if allowClose is true and then set allowClose back to true again.

@HostListener('document:click', ['$event'])
clickOutside(event: any) {
  if (!this.elementRef.nativeElement.contains(event.target) && this.allowClose) {
    this.handleClose();
  }
  this.allowClose = true;
}

That's it!

Daniel B
  • 8,770
  • 5
  • 43
  • 76
Michal Cumpl
  • 997
  • 7
  • 12
4

Please check if you are refreshing like ngIf or ngSwitch so that the child components vanish.So when you do parentComponent.contains(childComponent) it wont work in spite of being present when u had actually clicked.I had observed this yesterday where this code wont work and i had to do a workaround using this partially.Thanks.

  • 3
    That is the proper, simple answer. - `.contains()` won't work on elements that have `*ngIf` or `*ngSwitch` - simplest solution is to use `[hidden]='myVar'` binding, this will work like ng-hide from AngularJs, not removing element from DOM, but just making it not visible. More on `[hidden]='myVar'`: https://stackoverflow.com/a/35578093/1484847 – garfunkel61 Mar 23 '18 at 10:25