我试图尽可能地简化这个问题,所以忽略这个例子是多么毫无意义:)
我有一个显示计时器的指令。每 500 毫秒,它就会递增计数器。
.JS
.directive('testTimer', function($interval) {
return {
link: function(scope, el, attrs) {
var count;
scope.counter = 0;
count = $interval(tick, 500);
function tick() {
scope.counter++;
}
}
}
})
.HTML
<test-timer>{{counter}}</test-timer>
每次 tick() 运行时,我的控制器中的函数也会运行
.controller('testController', function($scope) {
$scope.array = [
1,2,3
]
$scope.getNumber = function(num) {
console.log('Why does this run every time tick runs?')
return num;
}
})
.HTML
<div ng-controller="testController">
<div ng-repeat="number in array">
{{getNumber(number)}}
</div>
<test-timer>{{counter}}</test-timer>
我尝试在我的$interval中使用 invokeApply = false,但计数器在 DOM 中没有更新。如何防止我的指令在控制器中一遍又一遍地运行其他函数,但仍让它更新视图中的计数器?
这是一个显示问题的JS小提琴(查看控制台日志)https://jsfiddle.net/marmite/nf4c18tx/
预期行为。
角度运行所谓的摘要循环来检测和传播变化。更新 {{ getNumber(number) }}
返回的值的唯一方法是评估函数调用getNumber(number)
,因为 Angular 不知道您是否更改了其返回值。摘要循环由$interval()
调用,是标准JavaScript setInterval()
的包装器。
您可以修改代码以仅使用 setInterval()
,并且可以看到不再调用 getNumber()
,因为没有任何东西可以触发摘要循环。
您更新的演示:https://jsfiddle.net/7Ljus149/1/
要回答您的问题:不要从函数返回数值。我不知道您的用例是什么,但我认为您不需要在{{ }}
中使用函数调用。它还可能导致严重的性能问题,一般来说,避免它几乎总是更好的。
我想我已经解决了这个特定情况
我将元素传递给指令的链接函数。
link: function(scope, el, attrs) {
然后,我可以手动更新它,而不是绑定计数器的值
angular.element(el[0]).html(counter++);
最后,我告诉我的$interval不要通过将 false 作为第 4 个参数传递来调用 App。
count = $interval(tick, 500, 0, false);
链接到固定的 JSFiddle https://jsfiddle.net/marmite/9ac5j76c/