2016-04-01 27 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