2017-04-25 30 views
1

我試圖在每次更新數據時更新其相應數據的視圖。Angular:當通過輸入裝飾器傳遞的數據對象發生更改時,不會更新

下面的所有示例都只是示例,它們不是我正在處理的代碼的嚴格副本,這些代碼太複雜了,無法在此處複製。

的數據是JSON請求,其具有對象的多維數組(陣列對象,每一個都與每個自身的屬性等)

[ 
    { 
     data_1: { 
      property_1: "some text 1", 
      property_2: "some text 1", 
      property_3: [ 
       { 
        deep_data: [ 
         0, 
         1, 
         2 
        ] 
       } 
       (...) 
      ] 
     } 
    }, { 
     data_2: { 
      property_1: "some text 2", 
      property_2: "some text 2", 
      property_3: [ 
       { 
        deep_data: [ 
         0, 
         1, 
         2 
        ] 
       } 
       (...) 
      ] 
     } 
    } 
    (...) 
] 

數據來自一個樣機單獨服務那被注入到主要部件中。

@Injectable() 
export class HttpPoll { 
    public received_data: any; 

    public fetchData() { 
     somehttp_request().subscribe(
      success => { 
       this.received_data = success; 
       this.new_data_was_received.next(true); 
      } 
     ); 
    } 
} 

這主要成分是負責創建整體模板,並將其從服務中的數據保存到一個公共財產「received_data」。

@Component({ 
    selector: "[main]", 
    template: `<div child [received_data]="received_data"></div>` 
}) 

export class MainComponent { 
    public received_data: any; 

    constructor(private data_gate: HttpPoll) { 
     this.data_gate.subscribe(
      data => this.received_data = data; 
     ); 
    } 
} 

該屬性在組件模板中用作@input修飾器以將該數據傳遞給子組件。

該子組件具有與由主組件傳遞的相同名稱的@input修飾符。

@Component({ 
    selector: "[child]", 
    template: `<div>{{ received_data.some_property }}</div>` 
}) 

export class ChildComponent { 
    @Input() received_data: any; 
} 

子組件沒有任何* ngFor,所以我不能使用任何trackBy方法。

子組件在頁面中顯示「received_data」,每次更改「received_data」時它都應該反映頁面中的更改。

如果有任何觸發角度更改檢測的調用(例如獲取「received_data」的週期性http請求),則一切正常。但是,一旦我在角度區域之外運行這些請求(使用runOutsideAngular),當收到新數據時,視圖不再更新。

@Injectable() 
export class HttpPoll { 
    public received_data: any; 

    constructor(private ngZone: NgZone) {} 

    public fetchData() { 
     this.ngZone.runOutsideAngular(() => { 
      somehttp_request().subscribe(
       success => { 
        this.received_data = success; 
        this.new_data_was_received.next(true); 
       } 
      ); 
     }) 
    } 
} 

我可以使它重新工作,如果我使用時,接收到新數據的區域中運行的指令,但現在它違背了使用runOutsideAngular點。

@Injectable() 
export class HttpPoll { 
    public received_data: any; 

    constructor(private ngZone: NgZone) {} 

    public fetchData() { 
     this.ngZone.runOutsideAngular(() => { 
      somehttp_request().subscribe(
       success => { 
        this.ngZone.run(() => { 
         this.received_data = success; 
         this.new_data_was_received.next(true); 
        }); 
       } 
      ); 
     }) 
    } 
} 

我已經測試方案時,視圖不會更新,並確認其主要成分是在其屬性保存新的數據,因爲它應該,但子組件永遠不會收到它。爲了測試這個,我在子組件中運行了一個計時器函數(這個計時器在runOutsideAngular內部,以便自己不觸發變化檢測)並記錄了子進程的@Input數據。該數據從未更改過一次。

我也嘗試過在子組件中使用ngOnChanges,但它從來沒有觸發過一次。

我嘗試過的另一件事是將檢測方法更改爲OnPush,但仍然沒有運氣。

這個問題的概要:在觸發角的變化檢測接收

數據=>主 成分保存新的數據傳遞到子組件=>子組件 更新與新的數據

查看在沒有觸發角度變化檢測的情況下接收的數據=>主 組件保存新數據傳遞給子組件=>子組件 不更新視圖並且從不接收新數據

如何確保子組件中的@Input數據在數據本身似乎不是從主組件傳遞到子組件時得到更新?理想情況下,我寧願不訴諸任何ngZone命令,使其再次工作。

回答

0

我想你誤解了runOutsideAngularZone的含義,或者我誤解了你正在嘗試做的事情。

基本上,你做的東西很重的角度區外。

類似下面的代碼,increaseProgress運行大量的超時功能的時間,我們儘量避免的角內運行,所以我們把它放在runOutsideAngular。但是,我們最終想知道結果。

這是從increaseProgress最終的回調,我們把它ngZone內使用zone.run

processOutsideAngularZone() { 
    this.progress = 0; 
    this.zone.runOutsideAngular(() => { 
    this.increaseProgress(() => { 
     this.zone.run(() => { 
     console.log('Outside Done!'); 
     }); 
    }); 
    }); 
} 

我建議你閱讀這篇https://blog.thoughtram.io/angular/2016/02/01/zones-in-angular-2.html

+0

嗨maxisam,示例我提供的僅僅是一個實例,但我正在處理每500ms(超過400次)發出的多個請求,每個請求觸發角度更改檢測並因此影響性能,這就是爲什麼這些請求不能觸發更改他們的o WN。目標是讓子組件也接收主組件通過@Input修飾器發送的更新數據,這是此問題的焦點。 – Shadow

+0

好吧,我沒有得到你想要的東西。你想跟蹤每500ms更新,但你不希望Angular檢測到更改?您希望子組件接收它,這意味着Angular需要檢測更改。 – maxisam

+0

順便說一句,您可以將您的所有請求合併到一個訂閱中,並且只對每個請求不進行任何重複更改。 – maxisam

相關問題