11

原文:我有一个使用 ng-repeat 生成的表,其中包含数百个由几个不同的 unix 时间戳组成的条目。我正在使用 moment.js 使它们显示为“19 分钟前”或很久以前。例如,我如何每五分钟更新一次,而不必刷新整个表(这需要几秒钟,并且会中断用户的排序和选择)。

4

5 回答 5

17

我使用以下过滤器。过滤器每 60 秒更新一次值。

angular
  .module('myApp')
  .filter('timeAgo', ['$interval', function ($interval){
    // trigger digest every 60 seconds
    $interval(function (){}, 60000);

    function fromNowFilter(time){
      return moment(time).fromNow();
    }

    fromNowFilter.$stateful = true;
    return fromNowFilter;
  }]);

并在 html

<span>{{ myObject.created | timeAgo }}</span>
于 2015-05-12T10:42:10.580 回答
13

I believe filters are evaluated every digest cycle, so using a filter to display your "time ago" strings might get CPU-expensive with hundreds of entries.

I decided to go with a pubsub architecture, using essentially eburley's suggested approach (mainly because I don't have to watch for $destroy events and manually unsubscribe), but with a NotificationService rather than a "Channel" function:

.factory('NotificationService', ['$rootScope',
function($rootScope) {
    // events:
    var TIME_AGO_TICK = "e:timeAgo";
    var timeAgoTick = function() {
        $rootScope.$broadcast(TIME_AGO_TICK);
    }
    // every minute, publish/$broadcast a TIME_AGO_TICK event
    setInterval(function() {
       timeAgoTick();
       $rootScope.$apply();
    }, 1000 * 60);
    return {
        // publish
        timeAgoTick: timeAgoTick,
        // subscribe
        onTimeAgo: function($scope, handler) {
            $scope.$on(TIME_AGO_TICK, function() {
                handler();
            });
        }
    };
}])

A time-ago directive registers/subscribes a timestamp (post.dt in example HTML below) with the NotificationService:

<span time-ago="post.dt" class="time-ago"></span>

.directive('timeAgo', ['NotificationService',
function(NotificationService) {
    return {
        template: '<span>{{timeAgo}}</span>',
        replace: true,
        link: function(scope, element, attrs) {
            var updateTime = function() {
                scope.timeAgo = moment(scope.$eval(attrs.timeAgo)).fromNow();
            }
            NotificationService.onTimeAgo(scope, updateTime); // subscribe
            updateTime();
        }
    }
}])

A few comments:

  • I tried to be efficient and not have the directive create a new scope. Although the directive adds a timeAgo property to the scope, in my usage, this is okay, since I only seem to use the time-ago directive inside an ng-repeat, so I'm just adding that property to the child scopes created by ng-repeat.
  • {{timeAgo}} will be examined every digest cycle, but this should be faster than running a filter
  • I also like this approach because I don't have a timer running on every timestamp. I have one timer running in the NotificationService.
  • Function timeAgoTick() could be made private, since likely only the NotificationService will need to publish the time ago event.
于 2013-08-08T00:23:18.360 回答
4

使用 Angular 的$timeout服务(只是一个包装器setTimeout())来更新您的数据。注意第三个参数,它表明 Angular 应该运行一个$digest循环来更新你的数据绑定。

这是一个示例: http: //jsfiddle.net/jandersen/vfpDR/
(此示例每秒更新一次,因此您不必等待 5 分钟即可看到它;-)

于 2013-08-02T05:47:05.390 回答
0

我为momentjs制作了一个包装器https://github.com/jcamelis/angular-moment

<p moment-interval="5000">{{"2014-05-21T14:25:00Z" | momentFromNow}}</p>

我希望这个对你有用。

于 2014-07-01T14:28:25.697 回答
0

我最终让 $scope.apply() 每五分钟被 setInterval 调用一次,它重新应用了将时间戳格式化为“x 分钟前”的过滤器。也许有点hacky,但它有效。我确定这不是最佳解决方案。

于 2013-08-02T22:03:42.127 回答