2017-06-01 41 views
4

我使用的是工具提示指令,所以当我点击<button>时 - 我动态插入并显示工具提示。Angular - 如何删除所有其他现有指令?

它工作得很好,我也看到了提示:

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删除它们,但是我想以角方式来实现它。

Full Plunker

顺便说一句 - 我会很高兴找到一个通用的解决方案也为组件和不仅为指令。 ( 如果可能的话)。

+2

https://开头plnkr。 co/edit/NU2FKlO6Q66bRde9m9AC?p = preview这里有一个更多的方法https://medium.com/@amcdnl/building-tooltips-for-angular2-396320fa938f检查此问题https://stackoverflow.com/questions/42598169/外接AC omponent动态地对一胎化元素使用-A-指令。 – yurzui

+1

:-) @yurzui一如既往,谢谢。 –

+0

@yurzui你可以请看看[这里](https://stackoverflow.com/questions/44530654/angular-service-injecting-dynamic-component)? –

回答

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

但是,如果你愿意使用服务(未测试的代码):

​​

而且你的指令将是这样的:

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

关于“正确的方法” - 你的意思是一个顶级(singleton)注入服务,该服务持有对每个可见弹出窗口的引用,该窗口监听“closeAll()”事件?然后遍历数组并在每个指令处调用'closeMe()'? –

+0

Sorta。但是你不需要'closeAll',因为只有一个活动。您应该让组件与服务对话说.. .. hiiii im现在活动的一个..并从服务,关闭以前(如果有),并设置一个说hiii活动之一 – PierreDuc

+0

服务不能_close_什么都没有。它会通过一个带有所选ref的主体(next)来发布(next())一个事件,并在每个指令的订阅处检查ref是否为this,如果不是则删除它自己。对 ? –

相关问题