AngularJS在ng-repeat中倒计时

时间:2013-04-24 23:56:48

标签: javascript angularjs

我有一个小型的AngularJS应用程序,用于搜索和检索用户列表以及下次安排的会议(假设一个在接下来的8小时内安排),使用时间格式为UTC的服务器从服务器返回,以便于计算到当地时间。每个用户可能具有不同的状态(忙碌直到x时间,自由直到x时间)。

我想要完成的是能够在剩余时间内更新DOM,直到会议安排完成或会议开始前的剩余时间。我有一些代码工作,但因为我显然没有正确地做这个只有结果集中的几个条目它使浏览器几乎停顿。任何建议将不胜感激!

我目前的代码包含以下代码段:

[主页]

<tr ng-repeat="item in pagedItems[currentPage-1] | orderBy:sortingOrder:reverse" ng-class="{success:item._freeBusy=='Free', error:item._freeBusy=='Busy'}">
       <td>{{item._firstName}}</td>
       <td>{{item._lastName}}</td>
       <td>{{item._facilityName}}</td>
       <td>{{item._extension}}</td>
       <td>{{item._description}}</td>
       <td><a ng-hide="!item._extension" ng-click="dial(item)">Dial</a></td>
       <td><button class="btn btn-primary" ng-click="openDetails(item)">Details</button></td>
       <td>{{item._freeBusy}} {{item._timeLeft}} {{calculateTime(item._freeBusyTime,$index)}}</td>
 </tr>

[控制器]

        $scope.timeUntil = function(s) {
        function isoToObj(s) {
            var b = s.split(/[-T+:]/i);
            return new Date(Date.UTC(b[0], --b[1], b[2], b[3], b[4], b[5]));
        }
        // Utility to add leading zero
        function z(n) {
            return (n < 10 ? '0' : '') + n;
        }
        // Convert string to date object
        var d = isoToObj(s);
        var diff = d - new Date();
        // Allow for previous times
        var sign = diff < 0 ? '-' : '';
        diff = Math.abs(diff);
        // Get time components
        var hours = diff / 3.6e6 | 0;
        var mins = diff % 3.6e6 / 6e4 | 0;
        var secs = Math.round(diff % 6e4 / 1e3);
        // Return formatted string
        return sign + z(hours) + ' Hours ' + z(mins) + ' Min' + ':' + z(secs);// + ':' + z(secs)
    }

    $scope.calculateTime = function(s, idx) {
        timeoutID = $timeout(function() {
            $scope.items[idx]._timeLeft = $scope.timeUntil(s);
            $scope.calculateTime(s, idx);
        }, 1000);
    };

修改

我理解下面提到的问题,我正在努力解决的问题是如何正确注册。因为它可能会多达15个以上的单独时间更新为单个刻度,这就是我迷路的地方。

3 个答案:

答案 0 :(得分:1)

您注册的时间超出了您的预期。每次使用angular渲染视图时,都会注册新的超时处理程序。添加回调计数器并观察计数:

$scope.called = 0;

$scope.calculateTime = function(s, idx) {
    timeoutID = $timeout(function() {
        $scope.items[idx]._timeLeft = $scope.timeUntil(s);
        $scope.calculateTime(s, idx);
        console.log(++$scope.called);
    }, 1000);
};

请参阅此插件我再现了错误:http://plnkr.co/edit/qJ4zDl6gc5C7Edg0T0gB。跑吧看看柜台吧。

为什么要在渲染周期中更新_timeLeft?为什么不这样做:

$scope.called = 0;

setInterval(function() {
  angular.forEach($scope.items, function function_name(item) {
    item._timeLeft = $scope.timeUntil(item._freeBusyTime);
  });
  console.log(++$scope.called);
  $scope.$apply();
}, 1000);

请参阅新的插件:http://plnkr.co/edit/rVJ6p4VXDQvt7rjT6eka

答案 1 :(得分:1)

你正在递归地调用$ scope.calculateTime!并且您正在修改ng-repeat期间的项目列表,这也会导致无限循环。

这个怎么样:http://plnkr.co/edit/0JqK96irV4ETdWZYxO3P?p=preview

更改了html以引用一个不影响ng-repeat的单独数组:

<td>in {{_timeLeft[$index]}}</td>

更新如下:

$scope._timeLeft = [];

var intervalID = window.setInterval(function() {
    for (var i=0; i<$scope.items.length; i++) {
      $scope._timeLeft[i] = $scope.timeUntil($scope.items[i]._freeBusyTime);
    }
    $scope.$apply();
}, 1000);

注意$ scope。$ apply()需要让Angular知道'_timeLeft'已被修改,它会更新对它的所有引用。

答案 2 :(得分:0)

我认为您不应该每次更新视图$timeout。 相反,您可以在控制器内倒计时,让视图显示计时器。

http://plnkr.co/edit/OUVdJyllzmVmPC0FhqYF?p=preview