当设置订阅的指令被销毁时,我在取消订阅主题时遇到问题。考虑以下 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
指令接收并@Input()
带有一个唯一 ID,该 ID 将用于识别哪些内容应该折叠/取消折叠,这是由*toggleCollapsibleContent
结构指令完成的。这 2 个指令之间的通信由名为 的服务处理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();
}
}
结构指令工作正常,因此实施的那一侧没有问题。所以问题是,假设我有 HTML 片段,HomeComponent
并且items
集合的长度为 2。这意味着我正在创建*toggleCollapsibleContent
结构指令的 2 个实例,每个实例都订阅togglerState$
主题。如果通过对象进行检查console.log
,togglerState$
我会发现我的对象有 2 个观察者,这是预期的行为,每个*toggleCollapsibleContent
.
但是,如果我转到另一条路线并渲染另一个组件等等,togglerState$
主题仍然存在,当我回到加载了我的/home
路线时HomeComponent
,toggerState$ 会增加 2 个观察者,并且由于原始观察者仍然存在,现在我有 4 个观察者,每个*toggleCollapsibleContent
指令实例 2 个,因此我的内容被复制了。
有谁知道为什么会这样?