我制作了一个新的指令,基本上是一个新的旋转木马,扩展了角度UI旋转木马引导程序。这个新的轮播将在一个框架中显示多个div。我的新指令接受数组中的任何数据和每个数据的自定义html模板。
但是,如果我将旋转木马与指令一起使用,我会在指令中看到一种奇怪的行为。一切正常,但我的指令中的手表始终为newVal
和oldVal
获得相同的值。我的意思是这,这是我的轮播代码:
<slide ng-repeat="frame in ctrl.frames">
<div ng-repeat="divs in frame.divs">
<custom-directive data="divs"></custom-directive>
</div>
</slide>
在我的customDirective
控制器内部,我会看到这样的数据更改:
$scope.$watch("ctrl.data", function(newVal, oldVal){
if (newVal !== oldVal) {
// data is updated, redraw the directive in my case
// however newVal is always the same as oldVal
}
})
newVal和oldVal始终相同。我希望初始状态为oldVal = undefined
,newVal
将是我的新数据。但是,事实并非如此。数据作为双向绑定传递给轮播和自定义指令(在每个指令的范围内使用'='运算符)。
为什么会这样?我已经对此进行了长时间的调查,这是我的发现:
ng-repeat
,则此将起作用。在初始状态期间,oldVal
将为undefined
,newVal
将成为我的数据。但为什么ng-repeat会导致这种情况?我已经阅读了大量关于原型继承的黄金法则的文章,其中说 ng-repeat将创建隐藏/隐藏父的新childScope,但这只发生在原始对象,我将数组传递给我的数据。我需要在我的carousel指令中使用ng-repeat ..所以我需要知道为什么ng-repeat导致这个..任何建议?
更新: 在Plunkr here中重现了这个问题。如您所见,oldValue始终与newValue相同(我希望oldValue在开始时未定义)
答案 0 :(得分:1)
我认为你遇到的问题只是对$watch
工作原理的误解。
$watch
期望以相等的值初始化。请参阅文档here。具体做法是:
在观察者注册范围后,监听器fn是 异步调用(通过$ evalAsync)来初始化观察者。在 在极少数情况下,这是不可取的,因为在何时调用侦听器 watchExpression的结果没有改变。检测这种情况 在监听器fn中,您可以比较newVal和oldVal。如果 这两个值是相同的(===)然后监听器被调用 初始化
换句话说,检查它们是否相等是因为不检测到初始调用
在你提供的Plunker中,如果你需要做一些初始化代码,你可以做两件事:
$watch
函数中 是否相等,如果是,那么这是初始调用的初始值link
函数中的该函数之外,值是它们的初始值(因为link
函数等同于post-link
,这意味着scope
值已经链接了)所以你可以把你的代码放在那里分叉您的Plunker here。请注意,我已将alert
移到$watch
之外,且值仍然有效
修改强>
如果它不在ng-repeat
中而且与Plunkr中已注释掉的代码一样设置,则会看到差异的原因是您在$timeout
中添加了数据。当页面最初加载时,以下两种类型呈现为:
<a1 prop="data[0]"></a1>
data=[]
。存在指令元素,使用link
调用data[0]=undefined
。 $watch
使用prop=undefined
<!-- ngRepeat: element in data track by $index -->
data
。不存在指令元素,这意味着link
不会被称为在超时后向data
添加项目时,它们如下所示:
<a1 prop="data[0]"></a1>
data[0]
,因此定义了prop
<div ng-repeat="element in data track by $index" class="ng-scope">
<a1 prop="element" class="ng-isolate-scope"></a1>
</div>
(x3)
link
,每个人都调用data
个函数。 $watch
调用prop
值已关联答案 1 :(得分:1)
当您在$watch
函数中注册link
时,Angular已在preLink
阶段处理了绑定,因此您第一次看不到undefined
执行watcher(初始化调用是oldVal和newVal可能相同的唯一时刻。如果观察者在绑定解析之前注册,则oldValue将为undefined
)
如果确实希望看到它,您可以覆盖compile
阶段并添加自定义preLink
方法(默认link
为{{ 1}})。
但我真的怀疑你想要那样做。为什么第一次没有未定义是一个问题?您应该尝试解释您面临的真正问题。
另请注意,如果传递给指令的postLink
是数组,则应使用divs
而不是scope.$watchColleciton
来检测数组元素中的更改而不是更改整个数组指针。