【问题标题】:Angular - How can I remove all other existing directives?Angular - 如何删除所有其他现有指令?
【发布时间】:2017-11-02 12:58:57
【问题描述】:

我正在使用工具提示指令,因此当我单击 <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;
    }
  }
} 

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

问题:

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

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

Full Plunker

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

【问题讨论】:

标签: javascript angular angular-directive


【解决方案1】:

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

但是让我们看看另一个不太明显的解决方案.. 这可能会令人不悦,但对于像这样的小事情,似乎真的是最简单易读的方法。要在 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;
  }
}

【讨论】:

  • 关于“正确的方法” - 你的意思是顶级(单例)注入服务,它包含对每个监听“closeAll()”事件的可见弹出窗口的引用?然后遍历数组并在每个指令处调用closeMe()
  • 排序。但是您不需要closeAll,因为只有一个处于活动状态。您应该让组件与服务对话说.. hiiii 现在是活动的.. 从服务中,关闭前一个(如果有),并设置一个说 hiii 的活动
  • 服务不能关闭任何东西。它只是通过带有所选参考(如您所说的活动的)的主题发布(下一个())一个事件,并且在每个指令的订阅处 - 它检查参考是否为this,如果不是 - 它会自行删除。对吧?
  • 我将使用服务添加“解决方案”。等一下:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-04
  • 2021-06-13
  • 2021-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多