当设置订阅的指令被销毁时,我在取消订阅主题时遇到问题。请考虑以下html:
<ng-container *ngFor="let item of items; let id = index">
<div [toggleCollapsible]="'target'+id">
{{ item.label }}
</div>
<div *toggleCollapsibleTarget="'target'+id">
<h1>Some nice content up in here</h1>
</div>
</ng-container>
toggleCollapsible
指令接收带有唯一ID的@Input()
,用于标识哪些内容应该崩溃/解除崩溃,这由*toggleCollapsibleContent
结构指令完成。这两个指令之间的通信由一个名为toggleCollapsibleService
的服务处理。
这里是toggleCollapsible
指令的一些代码。为了便于阅读,我省略了一些内容:
@Directive({
selector: "[toggleCollapsible]",
host: {
"(click)": "_onClick($event)",
}
})
export class toggleCollapsibleDirective {
@Input('toggleCollapsible') target: string;
isOpen: boolean;
constructor(private _toggle: toggleCollapsibleService) {}
_onClick(e) {
this._toggle.toggleContent(this.target, this.isOpen);
this.isOpen = !this.isOpen;
}
}
基本上,当单击主机元素时,调用接收2个参数的服务方法,目标名称以及可折叠当前是否打开。现在,我的toggleCollapsibleService
:
@Injectable()
export class toggleCollapsibleService {
targetName: string;
private togglerState$: Subject<boolean> = new Subject();
toggleContent(target: string, currentState: boolean) {
this.targetName = target;
this.togglerState$.next(!currentState);
}
}
所以,基本上这只是保存可折叠的ID,它将打开/关闭并传递相应的值(再次,它应该打开或关闭)。让我们看看*toggleCollapsibleContent
哪些事情变得棘手:
@Directive({
selector: "[toggleCollapsibleContent]"
})
export class toggleCollapsibleContentDirective {
private _name: string;
@Input("toggleCollapsibleContent")
set name(name: string) {
this._name = name;
this._toggle.togglerState$.subscribe(status => {
if (this._name == this._toggle.targetName && status) {
this.renderTarget();
} else if (this._name == this._toggle.targetName) {
this.unmountTarget();
}
});
}
constructor(
private _view: ViewContainerRef,
private _template: TemplateRef<any>,
private _toggle: toggleCollapsibleService
) {}
renderTarget() {
this._view.createEmbeddedView(this._template);
}
unmountTarget() {
if (this._view) this._view.clear();
}
}
结构指令工作正常,因此实现的那一方没有问题。问题是,假设我的HomeComponent
上有HTML代码段,而items
集合的长度为2.这意味着我创建了*toggleCollapsibleContent
结构的2个实例指令,每个订阅togglerState$
主题。如果通过console.log
检查togglerState$
对象,我得到的是我的对象有2个观察者,这是预期的行为,每个*toggleCollapsibleContent
实例一个。
但是,如果我转到另一个路线并渲染另一个组件,依此类推,togglerState$
主题仍然存在,当我返回到我/home
路线HomeComponent
时加载后,togglerState $增加了2个观察者,因为原来的观察者仍在那里,现在我有4个观察者,每个*toggleCollapsibleContent
指令实例2个,因此我的内容会重复。
有谁知道为什么会这样?
答案 0 :(得分:0)
您需要明确取消订阅:
this.subscription = this._toggle.togglerState$.subscribe(status => { ...
...
ngOnDestroy() {
this.subscription.unsubscribe();
}