2016-04-16 54 views
14

我正在为我的Angular 2应用程序创建一个“时间之前”的管道。Angular 2“ago ago”pipe

它应该将日期转换为诸如“5分钟前”或“60秒前”之类的字符串。它迄今为止效果很好,但在第一次计算后不会更新。如果给定日期例如是5秒前,则显示“5秒前”,但在此之后不会改变。

我已经尝试将管道的“纯”值设置为false,但这并没有帮助。

这里是我的代码:

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; 
    } 
} 

我使用这样的过滤器:

打字稿:

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> 
+1

你还可以展示你如何使用这个管道。 – sreeramu

回答

13

终于得到它的工作,很有挑战性,需要间隔的调整:)

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 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; 
     }); 
    }; 
} 
+0

完美的作品,谢谢!我认为让管道中的所有代码更好,并且不必在组件中使用超时函数。但它也更有效率吗?我完全不完全理解代码。 – user2611144

+0

我正在扩展'async'管道,它能够跟踪observables并更新视图。也许最好使用'async' [source](https://github.com/angular/angular/blob/60727c4d2ba1e4b0b9455c767d0ef152bcedc7c2/modules/angular2/src/common/pipes/async_pipe.ts)从零开始实现这样的管道。例如,但我没有足够的时间。 – kemsky

+1

它是否适用于角度2稳定版本?我在这一行中得到一个错误: 'export class MessageTimePipe extends AsyncPipe' =>'Type'any'不是构造函数类型' – Dee

0

我认为,它与你的管道无关b ut的方式Angular2检测到的变化。它检测基于引用的更改,即绑定引用是否更改,而不是更新其中的元素。

参见下面的示例:

@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); 
    } 
} 

参见thisx plunkr:https://plnkr.co/edit/kJdi1wx0iu9tDx8yTmRx?p=preview

+0

谢谢,我已经认为它必须做一些改变检测。但是,我怎么才能让我的代码工作呢?每秒重复更新一次数值?这可能会奏效,但我更喜欢更优雅的解决方案。 – user2611144

0

您需要更新'日期'参考以触发Angular2的变化检测,例如setTimeout(()=>this.date=new Date(), period),正如Thierry指出的那样。

你真的需要每秒更新吗? 根据您的使用情况,每60秒更新一次可能会足够好,并且可能会在前60秒显示“刚才”或“不到一分钟前”。

但是如果你真的想要秒,你只需要每60秒更新一次。 setTimeout(1000)然后可以变成setTimeout(60000),以最小化开销。

2

基于由@kemsky的出色答卷,我已经实现,修复了几个执行问题的管道的变体:

  • 将破坏
  • 当角2最终和开始
  • 停止轮询正常工作使用一个简单的b阿科夫减少轮询间隔与输出一致

你可以找到完整的管+规格代码在这个要点: https://gist.github.com/JohannesRudolph/8e6de056d9e33353f940d9da9e6ffd82

+0

这是非常好的,但它缺少“实时更新”部分,所以,而不是'return Observable.of(1)'我用'回到Observable.interval(1000).startWith(0)' –

7

我只是用这样的:

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

npm install time-ago-pipe --save 

然后在@NgModule中使用它:

import {TimeAgoPipe} from 'time-ago-pipe 

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

而且在模板:

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

不要重新发明轮子,除非你打算学习更多关于轮子。

+0

嘿那个链接,其中文件映射&包应该是原始的方法? –

+0

它不适用于ionic2 –

+0

@MuneemHabib我在Ionic 2应用程序中使用它。 –