2016-12-31 71 views
2

我遇到了一個非常奇怪的錯誤,我已經研究過,而且我很難找出答案。大多數我發現類似的項目在最終變更之前都有一年左右的時間,現在不工作。它被檢查之後2個組件之間的2路綁定僅適用於第一個字母

錯誤消息

表達發生了變化。先前的值:'Angular2'。當前值:'Angular2x'。

由於某種原因,它在2種方式綁定到屬性時拋出一個異常。

我認爲錯誤發生在下面的代碼運行後。

ngDoCheck(){ 
    this.bindingPropertyChange.emit(this.bindingProperty) 
    } 

我創建了一個Plunker來重現錯誤。 Plunker here

有誰知道爲什麼會發生這種情況?如果是這樣,你能解釋爲什麼拋出這個異常嗎?

+0

我可以建議其他辦法做到這一點? – micronyks

+0

當然,我想能夠使用2種方式綁定這個控制。 – JamTay317

+0

@ JamTay317,看看這個:https://plnkr.co/edit/nSymAOlvkOSdUx22gdrL?p=preview – Milad

回答

2

ngDoCheck是你的問題,這裏是原因:

ngDoCheck會在模型內部發生更改後觸發。

在您鍵入的字母后,角度開始檢查到處(整個應用程序)是否有任何相關的更改,並且Angular在更改後僅運行更改檢測一次,並且此後不應該有任何更新。雙向數據流,一個檢查)。

假設成功執行了更改檢測(ngDoCheck)並相應地更新了UI,但在檢查過程中,您突然做出了另一項更改。

開發模式,Angular2運行的第一個又一個changeDetection以確保沒有任何的第一個後已經改變了,因爲你發出的事件,可以改變模型再次悄無聲息,棱角分明是生氣,會拋出錯誤。

但是,在產品模式,Angular將不會運行第二次檢查,因此您不會在生產中看到此錯誤,但您的模型更新(emit)不會反映在UI中。 ,只需將ngCore.enableProdMode();添加到您的main.ts文件中,錯誤消失)。

下面是幾種方法來解決這個問題:

1-改變你的策略,就像在我First Plunker,你可以簡單地使用對象的綁定並繞過這個問題。

2-推遲了的setTimeout您的更改,這將運行另一個變化檢測,使角高興:

ngDoCheck(){ 
    setTimeout(()=>{ 
     this.bindingPropertyChange.emit(this.bindingProperty) 
    }); 

    } 

這裏是plunker

3-不要使用ngDoCheck,放出你的變化另一個使用(輸入)或(鍵盤)或類似事件的循環,這又使Angular運行另一個變化檢測:

注意我建議使用(輸入) up或keydown或類似的,原因是如果你使用keyup/keydown,更新不會是無縫的,因爲如果你按下一個鍵並按住它,更新將不會發生,直到你釋放鍵,但是(輸入),它會立即發生,就像你在評論中說的,如果用戶要用鼠標複製粘貼,他們沒有使用密鑰,也不會更新模型。

<input [(ngModel)]="bindingProperty" (input)="emitUp()" class="form-control"/> 

emitUp(){ 
    this.bindingPropertyChange.emit(this.bindingProperty) 
    } 

這裏是Plunker

+1

謝謝,這是非常有用的。我沒有使用你的第一個plunker,因爲我想重複使用這個控件的名字,地址,電子郵件......並通過發送一個對象並說obj.name對我來說看起來很靜態。但是,使用輸入的接口類似於比其他兩個選項更好的選項。因爲這可以重複使用,並且如果用戶使用鼠標複製粘貼,他們不會使用密鑰並且不會更新模型。 – JamTay317

+0

@ JamTay317,更新了答案並添加了更多有用的信息,乾杯 – Milad

1

我不是要說ngDoCheck任何合適的人,但似乎沒有與ngDoCheck問題。其他人可以建議,並可以編輯我的答案,以說出任何有關ngDoCheck

但截至現在你可以使用keyup事件,並綁定與它的功能,如下圖所示,

DEMOhttps://plnkr.co/edit/hSrPuWNyJd6Az8sHXh1T?p=preview

<input [(ngModel)]="bindingProperty" (keyup)="check()" class="form-control"/> 

check(){ 
    this.bindingPropertyChange.emit(this.bindingProperty) 
}