2016-04-16 269 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應用程序中使用它。 –