web-dev-qa-db-ja.com

Angular 2 "time ago"パイプ

私はAngular 2アプリケーション用の 'time ago'パイプを作成しようとしています。

日付を「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;
  }
}

私はこのようなフィルターを使用しています:

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>
27
user2611144

最後にそれを動作させ、非常に挑戦的で、間隔を微調整する必要があります:)

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;
        });
    };
}
20
kemsky

私はこれを使用しました:

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>

車輪についてさらに学習する予定がない限り、車輪を再発明しないでください。

27
David Prieto

@kemskyの優れた回答に基づいて、実装の問題をいくつか修正するPipeのバリアントを実装しました。

  • angular 2 final以降で適切に動作します
  • 破棄されるとポーリングを停止します
  • 単純なバックオフを使用して、出力と一致するポーリング間隔を短縮します

このGistで完全なパイプ+仕様コードを見つけることができます: https://Gist.github.com/JohannesRudolph/8e6de056d9e33353f940d9da9e6ffd82

4

これはあなたのパイプではなく、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

moment.jsソリューション。作業/テスト済み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 moment(d).fromNow();

    }
    ngOnDestroy(): void {
        this.removeTimer();
    }
    private removeTimer() {
        if (this.timer) {
            window.clearTimeout(this.timer);
            this.timer = null;
        }
    }
    private getSecondsUntilUpdate(seconds:number) {
        let min = 60;
        let hr = min * 60;
        let day = hr * 24;
        if (seconds < min) { // less than 1 min, update every 2 secs
            return 2;
        } else if (seconds < hr) { // less than an hour, update every 30 secs
            return 30;
        } else if (seconds < day) { // less then a day, update every 5 mins
            return 300;
        } else { // update every hour
            return 3600;
        }
    }
}
0
kenny

Thierryが指摘したように、たとえばsetTimeout(()=>this.date=new Date(), period)を使用して、Angular2の変更検出をトリガーするために「日付」参照を更新する必要があります。

毎秒本当に更新する必要がありますか?ユースケースによっては60秒ごとに更新するだけで十分な場合があり、最初の60秒間は「今」または「1分未満」と表示される場合があります。

ただし、本当に秒が必要な場合は、最初の60秒間は毎秒更新するだけで済みます。 setTimeout(1000)は、オーバーヘッドを最小化するためにsetTimeout(60000)になります。

0
Julien

AngularJs2で時間を取得する

このコマンドnpm install time-ago-pipe --saveを実行して、time-ago npmパッケージパッケージをangular applicationex:PS D:\ D\TimeAgo> npm install time-ago-pipe --save。このコマンドを実行した後、パッケージが追加されます。 「time-ago-pipe」からインポート{TimeAgoPipe}を追加する方法を示します; app.moduleで、TimeAgoPipeを宣言に入れます [コンポーネントからの入力を渡す o/p

0