2016-04-01 30 views
9

我真的很滿意你可以在組件的控制器中實現的「new」$ onChanges方法。然而,它似乎只是當綁定變量從我的組件外面被覆蓋觸發,而不是(例如)當一個項目被添加到現有的陣列

它這種預期的行爲或錯誤?有沒有另外一種方法來監聽輸入綁定的更新,除了執行$ scope。$ watch?

我使用角1.5.3

回答

16

首先TL; DR 對於經單向界結合的陣列,監視表達式補充說明的是不檢查對象的相等,但使用參考檢查。這意味着向數組添加一個元素將永遠不會觸發'$ onChanges'方法,因爲觀察者永遠不會'髒'。

我創建演示此一plnkr: http://plnkr.co/edit/25pdLE?p=preview

點擊「添加蔬菜外」和「改變陣列參考外」,並期待在「$ onChanges調用數」。它只會隨着後一個按鈕而改變。

完整說明 要完全掌握髮生了什麼,我們應該檢查角碼基礎。當找到'<'綁定時,以下代碼用於設置監視表達式。

case '<': 
     if (!hasOwnProperty.call(attrs, attrName)) { 
      if (optional) break; 
      attrs[attrName] = void 0; 
     } 
     if (optional && !attrs[attrName]) break; 

     parentGet = $parse(attrs[attrName]); 

     destination[scopeName] = parentGet(scope); 
// IMPORTANT PART // 
     removeWatch = scope.$watch(parentGet, function  parentValueWatchAction(newParentValue) { 
      var oldValue = destination[scopeName]; 
      recordChanges(scopeName, newParentValue, oldValue); 
      destination[scopeName] = newParentValue; 
     }, parentGet.literal); 
// ------------- // 
     removeWatchCollection.push(removeWatch); 
     break; 

這裏的重要部分是如何設置'scope。$ watch'表達式。傳遞的唯一參數是解析表達式和偵聽器函數。一旦在摘要週期中發現'$ watch'髒,偵聽器函數就會被觸發。如果它被觸發,監聽器將執行'recordChanges'方法。這會記錄'$ onChanges'回調任務,該任務將在'$ postDigest'階段執行,並通知所有正在偵聽'$ onChanges'生命週期鉤子的組件,以告訴它們值是否已更改。

這裏要記住的重要一點是,如果'$ watcher'從不骯髒,'$ onChanges'回調沒有被觸發。但更重要的是,通過創建'$ watch'表達式的方式,除非參考文件改變,否則它永遠不會變髒。如果您想檢查的對象,而不是基準之間的平等,你應該通過詢問這個額外的第三個參數:

$watch: function(watchExp, listener, objectEquality, prettyPrintExpression) 

由於這不是這裏的情況與方式的一種方式結合設置,它會一直檢查參考。

這意味着,如果向數組添加元素,則引用不會更改。這意味着'$ watcher'永遠不會變髒,這意味着'$ onChanges'方法不會被調用來改變數組。

爲了證明這一點,我創建了一個plnkr: http://plnkr.co/edit/25pdLE?p=preview

它包含兩個組件,外部和內部。 Outer具有原始字符串值,可以通過輸入框和可以通過添加元素或改變引用來擴展的數組進行更改。
Inner有兩個單向有界變量,值和數組。它會監聽所有更改。

this.$onChanges = setType; 
function setType() { 
    console.log("called"); 
    vm.callCounter++; 
} 

如果您在輸入字段中鍵入,每次都會觸發'$ onChanges'回調。這是合乎邏輯的和期望的,因爲字符串是原始的,所以它不能通過引用進行比較,這意味着'$ watcher'將變髒,'$ onChanges'生命週期鉤子被觸發。

如果你點擊「外添加蔬菜」,它將執行以下代碼:

this.changeValueArray = function() { 
     vm.valueArray.push("tomato"); 
    }; 

在這裏,我們只是一個值添加到現有的有限陣列。我們在這裏通過引用來工作,所以'$ watcher'沒有被解僱,並且沒有回調。您不會在控制檯中看到計數器增量或「調用」語句。

注意:如果在內部組件中單擊'將某物添加到數組',外部組件中的數組也會更改。這是合乎邏輯的,因爲我們通過引用更新完全相同的數組。所以即使它是單向綁定,也可以從內部組件內部更新數組。

如果通過單擊「更改外部數組引用」更改外部組件中的引用,則會按預期觸發'$ onChanges'回調。

至於回答你的問題:這是預期的行爲還是錯誤?我想這是預期的行爲。否則,他們會給你選擇以檢查對象相等性的方式來定義你的'<'綁定。你總是可以在github上創建一個問題,然後問問你是否願意。

+0

謝謝,我將在GitHub上創建一個問題 – jordydejong

+0

你絕對可以在這裏引用我的帖子。或者使用我的plnkr。 – KwintenP

+0

已創建:https://github.com/angular/angular.js/issues/14378 – jordydejong