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

时间:2017-06-01 11:38:44

标签: javascript angular angular-directive

我正在使用工具提示指令,因此当我点击<button>时 - 我会动态注入并显示工具提示。

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

enter image description here

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

@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;
    }
  }
} 

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

问题:

在插入新工具提示之前,如何“找到”所有现有工具提示并删除

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

Full Plunker

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

1 个答案:

答案 0 :(得分:3)

一个明显正确的答案是使用服务并让你的弹出窗口注入此服务并在打开和关闭时注册它,以了解当前弹出窗口是否打开。

但是让我们看一下另一个不那么明显的解决方案。这可能是不赞成的,但对于像这样的微小事情,它似乎是最简单易读的方式。要在Popover类上使用静态属性:

@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;
  }
}