2016-01-23 60 views
3

我在我的父'my-app'組件中使用了angular2組件'my-tree'。 「我的應用程序內」是如下:Angular2:嵌套* ngFor導致'檢查後表達式發生了變化'

@Component({ 
    selector: 'my-app', 
    providers: [], 
    template: ` 
    <my-tree *ngFor="#node of nodes" [title]="node"> 
     <my-tree *ngFor="#subNode of getSubNodes(node)" [title]="subNode"> 
     </my-tree> 
    </my-tree> 
    `, 
    directives: [MyTree] 
}) 
export class App { 
    constructor() { 
    this.nodes = ['Angular2', 'typescript', 'js']  
    } 

    getSubNodes(node: string) { 
    if(node === 'Angular2') { 
     return ['2.0.0', '1.4.2'] 
    } 
    if (node === 'typescript') { 
     return ['1.7.3']; 
    } 
    if (node === 'js') { 
     return ['es-6']; 
    }  
    } 
} 

我的樹是一個簡單的組件 -

@Component({ 
    selector: 'my-tree', 
    providers: [], 
    inputs: ['title'], 
    template: ` 
    <ul> 
     <li><span>{{title}}</span></li> 
     <ng-content></ng-content> 
    </ul> 
    `, 
    directives: [] 
}) 
export class MyTree { 
    private title: string; 

} 

當這樣執行,控制檯登錄與下面的錯誤 - 表達「getSubNodes(節點)在App @ 2:15'被檢查後發生了變化。以前的值:'2.0.0,1.4.2'。當前值:'2.0.0,1.4.2'。

有關實際代碼,請參見此plunk

我的代碼中的想法是創建一個樹(只是一個例子),第一個級別來自一個數組(硬編碼值),第二個級別來自一個函數,返回給定當前節點的下一個集合或價值)從第一級。 而且它調用這個函數的地方在角色抱怨表達式被檢查後被改變。雖然報告的值與錯誤消息中的前面的報告完全相同。 我在SO上搜索了這個錯誤,並且發現了很少的參考文獻,但是他們大多建議引用更改檢測。我無法理解爲什麼這是必需的,以及如何做到這一點。我還讀到,這只是一條診斷消息,並沒有在生產模式下拋出。

是不是可以在* ngFor中調用一個函數?應該做些什麼來擺脫這個錯誤?

回答

3

問題是

getSubNodes(node: string) { 
    if(node === 'Angular2') { 
     return ['2.0.0', '1.4.2'] 
    } 
    if (node === 'typescript') { 
     return ['1.7.3']; 
    } 
    if (node === 'js') { 
     return ['es-6']; 
    }  
    } 

這裏每次角檢查它得到一個新的數組實例的值,因此它們絕不相同。 Angular不會比較只有數組的實例相等的值。

該檢查也僅在開發模式下完成。 也What is difference between production and development mode in Angular2?

見這樣角應滿足

angular2 = ['2.0.0', '1.4.2']; 
typeScript = ['1.7.3']; 
js = ['es-6']; 

getSubNodes(node: string) { 
    if(node === 'Angular2') { 
     return this.angular2; 
    } 
    if (node === 'typescript') { 
     return this.typeScript; 
    } 
    if (node === 'js') { 
     return this.js; 
    }  
    } 
+0

好吧,現在我明白了錯誤信息的原因。但是定義總是滿足這個標準的返回值可能並不總是可能的。函數調用可能並不總是以這種方式總是返回。所以基本上這意味着功能不應該被使用? – tyrion

+4

您可以選擇@Component({changeDetection:ChangeDetectionStrategy.OnPush})'並通知Angular有關更改。見https://github.com/angular/angular/issues/4746或者實現'doCheck' https://angular.io/docs/js/latest/api/core/DoCheck-interface.html –

+1

這真的很有幫助。 – tyrion

1

的問題是,getSubNodes(node)違反了idempontent規則,因爲一個新的數組每個方法被調用時返回。

從模板語法開發者指南的Template Expressions section

模板表達式可以使或打破一個應用程序。請遵循這些準則,除非您有特別充分的理由在您完全理解的特定情況下將其分開。
....

冪等表達式

在角而言,冪等表達始終返回完全一樣的東西,直到它的相關值的變化之一。

在JavaScript虛擬機的一次轉動過程中,相關值不應改變。如果一個冪等表達式返回一個字符串或一個數字,它將在連續調用兩次時返回相同的字符串或數字。 如果表達式返回一個對象(包括Date或Array),則在連續調用兩次時返回相同的對象引用。

在發展模式,角會抱怨,如果冪等規定被違反,因爲在開發模式,模板綁定兩次檢查,發現此類違規的。 Angular試圖提供幫助,因爲如果您正在做一些不同的事情,比如修改在父組件中可見的應用程序狀態,那麼由於在更改檢測期間單次傳遞組件樹,該父組件的視圖不會更新。也就是說,一旦父組件檢查了更改,即使後代組件更改了父組件在其視圖/模板中綁定的某些數據,也不會再檢查它。

要解決該問題,請將代碼重做爲不違反規則。

相關問題