Angular.js - Apply filter using an interval

2019-06-18 16:20发布

问题:

I am using a custom angular.js filter for datetime objects:

function relativeTimeFilter()
{
    return function (dateObj) {
        return getRelativeDateTimeString(dateObj);
    };
}

function getRelativeDateTimeString(dt)
{
    if(!dt) return "undefined ago";

    var delta = dt.getSeconds();
    if (delta < 0) return "not yet";
    if (delta < 1 * 60) return delta == 1 ? "one second ago" : delta + " seconds ago";
    if (delta < 2 * 60) return "a minute ago";
    if (delta < 45 * 60) return Math.floor(delta/60) + " minutes ago";
    if (delta < 90 * 60) return "an hour ago";
    if (delta < 24 * (60*60)) return Math.floor(delta/60/60) + " hours ago";
    if (delta < 48 * (60*60)) return "yesterday";
    if (delta < 30 * (24 * (60*60))) return Math.floor(delta/60/60/24) + " days ago";
    if (delta < 12 * (30 * (24 * (60*60))))
    {
        var months = Math.floor(delta/60/60/24/30);
        return (months <= 1) ? "one month ago" : (months + " months ago");
    }
    else
    {
        var years = Math.floor(delta/60/60/24/365);
        return (years <= 1) ? "one year ago" : (years + " years ago");
    }
}

module.filter("relativetime", relativeTimeFilter);

At this point, it is not so important which filter I use (I think). The filter receives a Datetime object. The relative time declaration is only valid one second. Meaning one second ago must be updated after a second to 2 seconds ago and so on.

When I apply the filter, this only happens once. So how do I trigger the filter appliance in a regular interval?

I tried the following:

setInterval(function() {$scope.$apply()}, 1000) // placed in controller function

...with no success.

Any ideas?

回答1:

I don't think you are going to be able to achieve this with a filter. The reason $scope.$apply() doesn't work is because it is watching for changes on the data. Since the data didn't actually change, the filter never gets called again.

Instead, you need to adjust the data that is being viewed in your controller. Use $timeout instead of setInterval because it is built into the digestion lifecycle.

I'd consider using a directive to do this.

app.directive('relativeTime', function($timeout) {

  function update(scope, element) {
    element.text(getRelativeDateTimeString(scope.actualTime));
    $timeout(function() { update(scope, element); }, 1000);
  }

  return {
    scope: {
      actualTime: '=relativeTime'
    },
    link: function(scope, element) {
      update(scope, element);
    }
  };
});

So you can use the directive like this:

<div relative-time="theDate"></div>

Also, I found a flaw in your getRelativeDateTimeString function. You need to base your delta off of the current time. getSeconds just gives you the seconds of the given time:

var delta = parseInt(((new Date().getTime()) - dt.getTime()) / 1000);

Here is a working CodePen.



回答2:

Below is the working jsfiddle uses directive to update the time, I think you are looking for similar code..

http://jsfiddle.net/vishalvasani/xRg3j/

it uses

$timeout