サブスクリプションが設定されているディレクティブが破棄されたときにサブジェクトの登録を解除する際に問題が発生しています。ディレクティブが角4で破棄されたときに、オブザーバがSubjectから削除されない
<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
指令が受信し0*toggleCollapsibleContent
構造指令によって行われる/ uncollapse、崩壊すべきコンテンツを識別するために使用される一意のIDを持つ:次のHTMLを考えます。これらの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();
}
}
構造ディレクティブが正常に動作しているので、実装の側に問題はありません。問題は、HomeComponent
とitems
コレクションのHTMLスニペットが長さ2であると言うことができます。つまり、それぞれtogglerState$
Subjectにサブスクライブする*toggleCollapsibleContent
構造指示の2つのインスタンスを作成しています。 console.log
togglerState$
オブジェクトを調べると、私のオブジェクトには2人のオブザーバがあり、それぞれのインスタンスに対して1つずつ、*toggleCollapsibleContent
という動作が発生します。
しかし、私はそうで別のルートに移動し、別のコンポーネントをレンダリングした場合、togglerState$
件名はまだ存在しますが、私は戻ってHomeComponent
がロードされている私の/home
ルートに行くとき、togglerState $が2人の以上オブザーバーを追加し、以来、元のものはまだそこに残っていますが、私は今度は*toggleCollapsibleContent
ディレクティブの各インスタンスに対して2人のオブザーバを持っています。したがって、私のコンテンツは重複してしまいます。
これはどうして起こっているのでしょうか?
こんにちは、申し訳ありませんが、これは私のために働いていません:/「動作しない」はどのような –
は正確に意味ですか? –
オブザーバーはまだ登録されているので、私が '/ home'に戻ると、私はまだ重複のバグを受けています。私も[このアプローチ](https://stackoverflow.com/a/41177163/3949174)を試しましたが、完了ハンドラは実行されますが、私の問題は解決しません。 –