2016-07-08 5 views
0

アプリケーショングローバルサービスの値を変更するコンポーネントがあり、時々Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'というメッセージが表示されます。私はこれらが生産モードを有効にすることによって沈黙化できることを知っていますが、これを正しく行う方法を理解することを好むでしょう。親コンポーネントのビューの変更をもたらすObservableを正しく変更するにはどうすればよいですか?

TL; DR: I 容疑者これは何とか親が同様に変更されること変化検出器を伝えることにより解決することができるので、どのように私は変化を検出ツリーを歩くのですか?親と子の間に<router-outlet>があることは重要であるかもしれません。私はcompletly間違った理解を持っている場合には

十分な説明、: は、問題のコードは、おおよそ次のようになります。ChildComponentが満たされる必要がある2つのサブスクリプションを持っており、彼らは準備ができていたら、コンポーネントが表示され、いくつかの図であり、変数は意味のある値にリセットされます。

this._routeParams.params.subscribe(params => { 
    var pageId = params['pageId']; 
    this._projectService.activeProject 
     .subscribe(res => { 
      // Project is loaded, display the correct page to edit 
      this._project = res; 
      this._page = this._project.getPageById(pageId); 

      // The active page has changed: Reset render preview and sidebar 
      this.doRenderPreview = false; 
      // <<ERROR>> triggered by this line 
      this._sidebarService.showSidebar(SidebarComponent.SIDEBAR_IDENTIFIER); 
     }); 
}) 

SidebarService.showSidebar()への呼び出しは基本的に、実際にParentComponentにサイドバーをレンダリングするために使用され、このグローバルに利用SidebarServiceObservableを更新します。

// this.model is a BehaviourSubject 
showSidebar(newType : string, param? : any) { 
    if (!this.isKnownType(newType)) { 
     throw new Error(`Unknown sidebar type: ${newType}`); 
    } 

    this._model.next({ 
     type : newType, 
     param : param 
    }); 
} 

のみ表示状態に関する変更を伝播することを別の観測可能であり、これはサイドバーがあるかどうかを知ることが、詳細については気にしない必要があるコンポーネントのために重要です。エラーが発生した場合、サイドバーをレンダリングするために

get isSidebarVisible() : Observable<boolean> { 
    return (this._model.map(s => !!s)); 
} 

ParentComponentニーズそのレイアウトを更新するために、これは:

<!-- Error: Expression has changed after it was checked. Previous value: 'false'. Current value: 'true' --> 
<div *ngIf="isSidebarVisible | async" 
    class="sidebar"> 
    <sidebar-loader></sidebar-loader> 
</div> 
<div *ngIf="isSidebarVisible | async" 
    class="sidebar-hack"> 
    <!-- Dirty hack to ensure the main content is not too wide --> 
</div> 

isSidebarVisible性は、単にグローバルサービスへのショートカットである:

get isSidebarVisible() { 
    return (this._sidebarService.isSidebarVisible); 
} 

l 容疑者Editorコンポーネントの結果が親コンポーネントの変更になります。しかし、私は他の場所で同様のコードを持っていますが、このシナリオの主な違いはかもしれません<router-outlet>経由で子供が読み込まれているということですか?

編集this._sidebarService.isSidebarVisible.subscribe(v => this._sidebarVisible = v);を:親でasyncビュー内のパイプ、代わりに「キャッシュ」isSidebarVisibleを回避し、サブスクリプションを経由して、それを更新するときの動作は同じです。しかし、私はあなたが多分どちらかにisSidebarVisibleを設定し、グローバル変数に観測可能に購読を設定すべきだと思うhttps://toddmotto.com/component-events-event-emitter-output-angular-2

:あなたが持つEventEmitterを使用する場合がありますツリー、ここでガイドを変更を伝播するために

答えて

1

trueまたはfalseを設定し、isSidebarVisible: boolean = false;を単純なブール値に設定します。サイドバーが表示されたら、この値をtrueに設定するだけです。

+0

あなたの提案をありがとう、私はそれに応じて投稿を更新しました。悲しいことに、コンポーネントにサブスクリプションを引き寄せても役に立たなかった場合でも、エラーはまったく同じです。私が理解していることから、 'EventEmitter'を使うことは' 'を越えて動作しません。または私は間違っていますか? –

+0

それはうまく動作しますが、私たちは仕事で使っていますが、そのためのラッパーを作成したいかもしれません – Colum

1

解決方法は、変更検出が発生したことを通知する必要があります。ParentComponentだから、

  • を注入ChangeDetectorあなたのコンポーネントにすることができます constructor(private cd: ChangeDetectorRef) {}

  • _sidebarService.isSidebarVisibleの変化に登録して、レイアウトを更新し、変更を検出するためのコンポーネントマークする:ここで

ngOnInit() { 
    this._sidebarService.isSidebarVisible.subscribe((visibility) => { 
     this.visibility = visibility; // application state changed 
     this.cd.markForCheck(); // marks path 
    }) 
} 

を詳細は次のとおりです。http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html

+0

これはちょうど私が必要とするようなものでしたが、何らかの理由で 'markForCheck()エラーについては何も変更されません。 –

関連する問題