在 $watch 中使用 $apply

Using a $apply inside a $watch

我有一个非隔离作用域指令。我不想隔离它,因为它需要与其他指令一起位于元素上。但是我需要看范围内的项目。所以我尝试了这个:

scope.$watch(function() {
     return scope.$apply(attrs.myAttribute);
}, function(val) {
     return val ? doSomething():doSomethingElse();
});

这不起作用,因为 angular 抛出摘要循环已在进行中错误。所以我的问题是,如何使用非隔离指令动态监视范围内的项目。

谢谢,

如果项目已经在范围内,则不完全确定您在观看该项目时遇到的困难是什么。你能详细说明一下吗?无论如何,这里有两个解决方案应该涵盖几乎所有情况。要观察属性变化,请观察以下...

scope.$watch(function() {
    return elem.attr('my-attribute');
}, function(n, o) {
    if(n) 
        console.log(n);
});

JSFiddle Link - 观看属性演示


但是,我怀疑您很难将项目纳入范围。如果是这样,这里有一种方法可以通过 $observe 分配它,然后在没有隔离的情况下从那里观看它...

attrs.$observe('myAttribute', function(value) {
    scope.myValue = value;
});

scope.$watch('myValue', function(n, o) {
    if(n) 
        console.log(n);
});

JSFiddle Link - 通过 $observe

观看属性演示

您不想在 $watch 回调中调用 $apply,因为 scope.$watch 会在内部为您调用 $apply,这就是为什么您会得到 "digest cycle already in progress error"错误。

相反,你可以简单地做:

scope.$watch(attrs.myAttribute, function(val){
  return val ? doSomething() : doSomethingElse();
};

设置为 myAttribute 的表达式将根据指令所在元素的范围进行评估,因为正如您提到的那样,它不是孤立的。当 return 值改变时,回调函数将被调用。

例如,如果您的 HTML 看起来像这样

<div myNoNewScopeDirective myAttribute="doThis(value)"></div>

doThis(value) 将根据与 div 元素关联的范围进行评估,其 return 值将由您的 myNoNewScopeDirective 监视。因此,对此类值的任何更改都将触发您提供的回调,当 val 为真时,将调用 doSomething