Нажмите вне директивы с помощью ngIf? - PullRequest
1 голос
/ 01 ноября 2019

Я использую следующую директиву для обнаружения и скрытия блока, если щелчок был вне конкретного элемента DOM:

import {
  Directive,
  ElementRef,
  Output,
  EventEmitter,
  HostListener
} from "@angular/core";

@Directive({
  selector: "[clickOutside]"
})
export class ClickOutsideDirective {
  constructor(private _elementRef: ElementRef) {}

  @Output()
  public clickOutside = new EventEmitter();

  @HostListener("document:click", ["$event.target"])
  public onClick(targetElement) {
    const clickedInside = this._elementRef.nativeElement.contains(
      targetElement
    );

    this.clickOutside.emit(clickedInside);
  }
}

Я применил эту директиву к элементу:

<div class="action" (click)="open()">Open</div>
<div
    class="search_content"
    *ngIf="_searchContentOpen"
    clickOutside
    (clickOutside)="clickOutside($event)"
  ></div>

Код компонента:

open(): void {
   this._searchContentOpen = !this._searchContentOpen;
}

Проблема в том, что когда я вызываю щелчок, я устанавливаю this._searchContentOpen в true / false.

В зависимости от этого я показываю блок, гдеДиректива применяется. Но директива работает всегда также в шаге, когда работает ngIf. Так как блок результата никогда не показывается.

Как это исправить?

1 Ответ

2 голосов
/ 01 ноября 2019

Вот мои два варианта:

1) использование event.stopPropagation() на триггере

<div class="action" (click)="open(); $event.stopPropagation()">Open</div>

2) щелчок ручки только после применения директивы

@Directive({
  selector: '[clickOutside]'
})
export class ClickOutsideDirective implements OnInit {
  @Output() clickOutside = new EventEmitter();

  captured = false;

  constructor(private elRef: ElementRef) { }

  @HostListener('document:click', ['$event.target'])
  onClick(target) {
    if (!this.captured) {
      return;
    }

    if (!this.elRef.nativeElement.contains(target)) {
      this.clickOutside.emit();
    };
  }

  ngOnInit() {
    fromEvent(document, 'click', { capture: true }).pipe(take(1))
      .subscribe(() => this.captured = true);

    /* or
    document.addEventListener('click', () => this.captured = true, { 
      capture: true,
      once: true
    });
    */
  }
}

Ng-run Пример

...