Angular - 如何删除所有其他现有指令?

Angular - How can I remove all other existing directives?

我正在使用工具提示指令,所以当我单击 <button> - 我动态注入并显示工具提示。

它运行良好,我确实看到了工具提示:

这是我用来在单击按钮时插入工具提示的代码:

@Directive({ selector: '[popover]'})
class Popover {
  private _component: ComponentRef<>;
    constructor(private _vcRef: ViewContainerRef, private _cfResolver: ComponentFactoryResolver,private elementRef: ElementRef) {
    }
    @HostListener('click')
  toggle() {
    if (!this._component) {
      const componentFactory = this._cfResolver.resolveComponentFactory(PopoverWindow);
      this._component = this._vcRef.createComponent(componentFactory);

    } else {
      this._vcRef.clear()
      this._component.destroy();
      this._component = null;
    }
  }
} 

但我希望屏幕上出现多个工具提示。
换句话说,在我注入工具提示之前 - 我想删除所有现有的工具提示 - 如果有的话。

问题:

如何 "find" 所有现有工具提示并 删除 它们,然后再插入新工具提示?

我知道我可以为每个添加一个 class,然后通过 removeNode 删除它们,但我想以 Angular 的方式进行。

Full Plunker

顺便说一句 - 我很乐意为组件找到一个通用的解决方案,而不仅仅是指令。 (如果可能的话)。

一个显而易见的正确答案是使用一项服务并让您的弹出窗口注入此服务并在它们打开和关闭时向其注册,以了解当前是否有打开的弹出窗口。

但让我们看看另一个不太明显的解决方案.. 这可能会让人不悦,但对于像这样的小事情,似乎确实是最简单易读的方法。要在 Popover class 上使用静态 属性:

@Directive({ selector: '[popover]'})
class Popover {
  private static currentPopover: Popover;

  private get active() {
      return this === Popover.currentPopover;
  } 

  private component: ComponentRef<any>;

  constructor(
       private vcRef: ViewContainerRef, 
       private cfResolver: ComponentFactoryResolver,
       private elementRef: ElementRef
  ) {}

  @HostListener('document:click')
  onDocClick() {
    if (this.active) {
      this.close();
    }
  }

  @HostListener('click', ['$event'])
  toggle(event: MouseEvent) {
    if (Popover.currentPopover && !this.active) {
      Popover.currentPopover.close();
    } 
    if (!this.active) {
      this.open();
      event.stopImmediatePropagation();
    }
  }

  open() {
    const componentFactory = this.cfResolver.resolveComponentFactory(PopoverWindow);
    this.component = this.vcRef.createComponent(componentFactory);
    Popover.currentPopover = this;
  }

  close() {
    this.vcRef.clear()
    this.component.destroy();
    this.component = null;
    Popover.currentPopover = undefined;
  }
} 

我还添加了一个文档点击侦听器,因此当您点击其他任何地方时,它会关闭当前弹出窗口。

plunkr

但如果您愿意使用服务(未经测试的代码):

export class PopoverService {

    private activePopover: Popover;

    public setActive(popover: Popover): void {
        if (this.activePopover) {
            this.activePopover.close();
        }
        this.activePopover = popover;
    }   

    public isActive(popover: Popover): boolean {
       return popover === this.activePopover;
    }
}

您的指令将如下所示:

@Directive({ selector: '[popover]'})
class Popover {

  private get active() {
      return this.popoverService.isActive(this);
  } 

  private component: ComponentRef<any>;

  constructor(
       private vcRef: ViewContainerRef, 
       private cfResolver: ComponentFactoryResolver,
       private elementRef: ElementRef,
       private popoverService: PopoverService
  ) {}

  @HostListener('document:click')
  onDocClick() {
    if (this.active) {
       this.close();
    }
  }

  @HostListener('click', ['$event'])
  toggle(event: MouseEvent) {
    if (!this.active) {
       this.open();           
       event.stopImmediatePropagation();
    }
  }

  open() {
    const componentFactory = this.cfResolver.resolveComponentFactory(PopoverWindow);
    this.component = this.vcRef.createComponent(componentFactory);
    this.popoverService.setActive(this);
  }

  close() {
    this.vcRef.clear()
    this.component.destroy();
    this.component = null;
  }
}