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