Подтвердить что ты не робот

Обновление значений "время назад" в Angularjs и Momentjs

Оригинал: У меня есть таблица, сгенерированная с помощью ng-repeat с сотнями записей, состоящих из нескольких временных меток unix. Я использую moment.js, чтобы они отображались как "19 минут назад", или как-то давно это было. Как бы я мог обновить эту информацию каждые пять минут, например, без необходимости обновлять всю таблицу (что занимает несколько секунд и прерывает сортировку и выбор пользователей).

4b9b3361

Ответ 1

Я использую следующий фильтр. Фильтр обновляет значение каждые 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>

Ответ 2

Я полагаю, что фильтры оцениваются каждый цикл дайджеста, поэтому использование фильтра для отображения ваших строк "время назад" может стать дорогостоящим CPU с сотнями записей.

Я решил пойти с архитектурой pubsub, используя, по существу, предлагаемый подход eburley (в основном потому, что мне не нужно следить за $destroy события и ручная отмена подписки), но с функцией NotificationService, а не с функцией "Channel":

.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 регистрирует/подписывает метку времени (post.dt в примере HTML ниже) с 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();
        }
    }
}])

Несколько комментариев:

  • Я старался быть эффективным и не имел директивы для создания новой области. Хотя директива добавляет свойство timeAgo в область видимости, в моем использовании это нормально, так как я только, кажется, использую директиву time-ago внутри ng-repeat, поэтому я просто добавляю это свойство в дочерние области созданный ng-repeat.
  • {{timeAgo}} будет проверяться каждый цикл дайджеста, но это должно быть быстрее, чем запуск фильтра
  • Мне также нравится этот подход, потому что у меня нет таймера, работающего на каждой отметке времени. У меня есть один таймер, запущенный в NotificationService.
  • Функция timeAgoTick() может быть сделана закрытой, поскольку, вероятно, только NotificationService нужно будет опубликовать событие time ago.

Ответ 3

Используйте angular $timeout сервис (только обертка вокруг setTimeout()) для обновления ваших данных. Обратите внимание, что третий параметр, который указывает, что angular должен запустить цикл $digest, который будет обновлять привязки данных.

Вот пример: http://jsfiddle.net/jandersen/vfpDR/
(Этот пример обновляется каждую секунду, поэтому вам не нужно ждать 5 минут, чтобы увидеть его; -)

Ответ 4

У меня получилось, что $scope.apply() вызывается каждые пять минут с помощью setInterval, который повторно фильтрует форматирование временных меток в "x минуты назад". Может быть, немного взломанный, но он работает. Я уверен, что это не оптимальное решение.

Ответ 5

Я сделал обертку для momentjs https://github.com/jcamelis/angular-moment

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

Я надеюсь, что это сработает для вас.