2016-07-08 39 views
0

我有一個組件可以更改應用程序全局服務中的值,並且有時會看到Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'消息。我知道這些可以通過啓用生產模式來消除,但我更願意瞭解如何正確執行此操作。如何正確更改導致父組件中的視圖更改的`Observable`?

TL;博士:嫌疑這可以通過某種方式告訴變化檢測父也將改變,解決了,讓我怎麼走了變化檢測樹?家長和孩子之間有一個<router-outlet>可能也可能不重要。

充分說明,如果我有一個完全地錯誤的認識: 有問題的代碼大致是這樣的:該ChildComponent有兩個訂閱需要得到滿足,一旦他們已經準備好,顯示組件和一些看法變量重置爲有意義的值。

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()呼叫基本更新此全局可用SidebarService然後將其用於實際呈現在ParentComponent側欄的一個Observable

// 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); 
} 

嫌疑人即問題是Editor組件導致更改它的父組件。但我在其他地方也有類似的代碼,這種情況下的主要區別可能是是孩子通過<router-outlet>加載?

編輯this._sidebarService.isSidebarVisible.subscribe(v => this._sidebarVisible = v);:避免在視圖中async管,而是「緩存」 isSidebarVisible父,並通過訂閱更新時的行爲是一樣的。

回答

1

要傳播的變化了,你可能想使用EventEmitter,這裏的指南樹:https://toddmotto.com/component-events-event-emitter-output-angular-2

但是,我想你也許應該設立一個訂閱觀察到在全局變量設置isSidebarVisible要麼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()'不會改變有關錯誤的任何信息。 –