2017-07-20 18 views
1

サブスクリプションが設定されているディレクティブが破棄されたときにサブジェクトの登録を解除する際に問題が発生しています。ディレクティブが角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(); 
    } 
} 

構造ディレクティブが正常に動作しているので、実装の側に問題はありません。問題は、HomeComponentitemsコレクションのHTMLスニペットが長さ2であると言うことができます。つまり、それぞれtogglerState$ Subjectにサブスクライブする*toggleCollapsibleContent構造指示の2つのインスタンスを作成しています。 console.logtogglerState$オブジェクトを調べると、私のオブジェクトには2人のオブザーバがあり、それぞれのインスタンスに対して1つずつ、*toggleCollapsibleContentという動作が発生します。

しかし、私はそうで別のルートに移動し、別のコンポーネントをレンダリングした場合、togglerState$件名はまだ存在しますが、私は戻ってHomeComponentがロードされている私の/homeルートに行くとき、togglerState $が2人の以上オブザーバーを追加し、以来、元のものはまだそこに残っていますが、私は今度は*toggleCollapsibleContentディレクティブの各インスタンスに対して2人のオブザーバを持っています。したがって、私のコンテンツは重複してしまいます。

これはどうして起こっているのでしょうか?

答えて

0

あなたは明示的に解除する必要があります。

this.subscription = this._toggle.togglerState$.subscribe(status => { ... 

... 

ngOnDestroy() { 
    this.subscription.unsubscribe(); 
} 
+0

こんにちは、申し訳ありませんが、これは私のために働いていません:/「動作しない」はどのような –

+1

は正確に意味ですか? –

+0

オブザーバーはまだ登録されているので、私が '/ home'に戻ると、私はまだ重複のバグを受けています。私も[このアプローチ](https://stackoverflow.com/a/41177163/3949174)を試しましたが、完了ハンドラは実行されますが、私の問題は解決しません。 –

関連する問題