Angular 2 “time ago” pipe

I am trying to create a ‘time ago’ pipe for my Angular 2 application.

It should transform a date to a string such as ‘5 minutes ago’ or ’60 seconds ago’. It works nicely so far, but it doesn’t update after the first calculation. If the given date is for example 5 seconds ago, it displays ‘5 seconds ago’ but never changes after that.

I have already tried setting the pipes ‘pure’ value to false but that didn’t help.

Here is my code:

import {Pipe, PipeTransform} from 'angular2/core';

@Pipe({
  name: 'messageTime',
  pure: false
})
export class MessageTimePipe implements PipeTransform {
  transform(value: Date, []): string {
    var result: string;

    // current time
    let now = new Date().getTime();

    // time since message was sent in seconds
    let delta = (now - value.getTime()) / 1000;

    // format string
    if (delta < 10) {
      result = 'jetzt';
    } else if (delta < 60) { // sent in last minute
      result = 'vor ' + Math.floor(delta) + ' Sekunden';
    } else if (delta < 3600) { // sent in last hour
      result = 'vor ' + Math.floor(delta / 60) + ' Minuten';
    } else if (delta < 86400) { // sent on last day
      result = 'vor ' + Math.floor(delta / 3600) + ' Stunden';
    } else { // sent more than one day ago
      result = 'vor ' + Math.floor(delta / 86400) + ' Tagen';
    }

    return result;
  }
}

I’m using the filter like this:

TypeScript:

import {Component, Input} from 'angular2/core';
import {MessageTimePipe} from '../../pipes/message-time.pipe';

@Component({
  selector: 'message-item',
  pipes: [MessageTimePipe],
  templateUrl: 'build/components/message-item/message-item.component.html'
})
export class MessageItemComponent {
  @Input()
  message: JSON;

  date: Date;

  ngOnInit() {

   this.date = new Date(2016, 3, 16, 12, 49, 10);
  }
}

HTML:

<p class="time">
  {{ date | messageTime }}
</p>

7
Leave a Reply

avatar
7 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
Jason Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
Jason
Guest

Use ngx-moment https://github.com/urish/ngx-moment, a pipe integration with Momentjs, with i18n support

Jason
Guest

Finally got it working, quite challenging and requires interval tweaking:) import {Pipe, ChangeDetectorRef} from 'angular2/core'; import {Observable} from 'rxjs/Observable'; import {AsyncPipe} from 'angular2/common'; @Pipe({ name: 'messageTime', pure: false }) export class MessageTimePipe extends AsyncPipe { value:Date; timer:Observable<string>; constructor(ref:ChangeDetectorRef) { super(ref); } transform(obj:any, args?:any[]):any { if (obj instanceof Date) { this.value = obj; if(!this.timer) { this.timer = this.getObservable(); } return super.transform(this.timer, args); } return super.transform(obj, args); } private getObservable() { return Observable.interval(1000).startWith(0).map(()=> { var result:string; // current time let now = new Date().getTime(); // time since message was sent in seconds let delta = (now - this.value.getTime()) / 1000; // format… Read more »

Jason
Guest

I just used this:

https://www.npmjs.com/package/time-ago-pipe

npm install time-ago-pipe --save

Then in the @NgModule you want to use it in:

import {TimeAgoPipe} from 'time-ago-pipe

@NgModule({
    imports: [... etc ...],
    declarations: [AppComponent, ...etc..., TimeAgoPipe],
    bootstrap: [AppComponent]
})

And in the template:

<span>{{your_date | timeAgo}}</span>

Don’t reinvent the wheel, unless you plan on learning more about wheels.

Jason
Guest

I think that it’s not related to your pipe but to the way Angular2 detects changes. It detects changes based on references, i.e. if bound references change and not if elements in them are updated. See the following sample: @Component({ selector: 'my-app', template: ` <div>{{val | pdate}}</div> `, pipes: [ DatePipe ] }) export class AppComponent { constructor() { this.val = new Date(); setTimeout(() => { this.val = new Date(); // Updates view }, 1000); setTimeout(() => { this.val.setTime((new Date().getTime()); // Doesn't update view }, 2000); } } See thisx plunkr: https://plnkr.co/edit/kJdi1wx0iu9tDx8yTmRx?p=preview.

Jason
Guest

You need to update the ‘date’ reference to trigger Angular2’s change detection, with a setTimeout(()=>this.date=new Date(), period) for instance, as Thierry pointed out.

Do you really need an update every second?
Updating every 60 seconds might be good enough depending on your use case, and could display ‘just now’ or ‘less than a minute ago’ for the first 60 seconds.

But if you really want the seconds, you only need to update every seconds for the first 60 seconds. The setTimeout(1000) can then become setTimeout(60000), to minimizes overhead.

Jason
Guest

Get Time-Ago in AngularJs2

You need to run this command npm install time-ago-pipe –save to install the time-ago npm package package in your angular application
ex : PS D:DTimeAgo> npm install time-ago-pipe –save. After run this command the package will added.
Image shows how to add import {TimeAgoPipe} from ‘time-ago-pipe’; in app.module and put TimeAgoPipe in Declarations[Pass input from componento/p

Jason
Guest

A moment.js solution. Working/tested in Angular 6: import { ChangeDetectorRef, NgZone, Pipe, PipeTransform } from '@angular/core'; import * as moment from 'moment'; moment.locale("de"); // set your language @Pipe({ name:'timeago', pure:false }) export class TimeagoPipe implements PipeTransform { private timer: number; constructor(private changeDetectorRef: ChangeDetectorRef, private ngZone: NgZone) {} transform(value:string) { this.removeTimer(); let d = new Date(value); let now = new Date(); let seconds = Math.round(Math.abs((now.getTime() - d.getTime())/1000)); let timeToUpdate = (Number.isNaN(seconds)) ? 1000 : this.getSecondsUntilUpdate(seconds) *1000; this.timer = this.ngZone.runOutsideAngular(() => { if (typeof window !== 'undefined') { return window.setTimeout(() => { this.ngZone.run(() => this.changeDetectorRef.markForCheck()); }, timeToUpdate); } return null; }); return… Read more »