更新Angular $ interval中的变量会导致其他函数运行

时间:2016-02-11 12:06:37

标签: javascript angularjs

我试图尽可能地简化这个问题,所以忽略这个例子是多么无意义:)

我有一个显示计时器的指令。每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/

2 个答案:

答案 0 :(得分:1)

这是预期的行为。

Angular运行所谓的digest loop来检测和传播更改。更新{{ getNumber(number) }}返回值的唯一方法是评估函数调用getNumber(number),因为Angular不知道您是否更改了其返回值。摘要循环由$interval()调用,https://jsfiddle.net/7Ljus149/1/是标准JavaScript setInterval()的包装。

您可以修改代码以仅使用setInterval(),并且您可以看到getNumber()不再被调用,因为没有任何内容可以触发摘要循环。

您的最新演示:{{3}}

回答你的问题:不要从函数返回数值。我不知道你的用例是什么,但我认为你不需要在{{ }}中使用函数调用。它也可能导致严重的性能问题,一般来说,避免它会更好。

答案 1 :(得分:0)

我想我已经解决了这个具体案例

我将元素传递给指令的链接函数。

link: function(scope, el, attrs) {

然后,我可以手动更新它,而不是绑定计数器的值

angular.element(el[0]).html(counter++);

最后,我通过传递false作为第4个参数来告诉我的$ interval不调用Application。

count = $interval(tick, 500, 0, false);

链接到固定的JSFiddle https://jsfiddle.net/marmite/9ac5j76c/