J'essaie de créer un tuyau "time ago" pour mon application Angular 2.
Il convient de transformer une date en chaîne telle que "5 minutes auparavant" ou "60 secondes auparavant". Cela fonctionne bien jusqu'à présent, mais il ne se met pas à jour après le premier calcul. Si la date donnée est par exemple il y a 5 secondes, il affiche «Il y a 5 secondes» mais ne change jamais par la suite.
J'ai déjà essayé de définir la valeur "pure" des canaux sur false, mais cela n'a pas aidé.
Voici mon 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;
}
}
J'utilise le filtre comme ceci:
Manuscrit:
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>
Enfin réussi à le faire fonctionner, assez difficile et nécessite des ajustements d'intervalle :)
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;
});
};
}
Je viens d'utiliser ceci:
https://www.npmjs.com/package/time-ago-pipe
npm install time-ago-pipe --save
Ensuite, dans le @NgModule, vous souhaitez l'utiliser:
import {TimeAgoPipe} from 'time-ago-pipe
@NgModule({
imports: [... etc ...],
declarations: [AppComponent, ...etc..., TimeAgoPipe],
bootstrap: [AppComponent]
})
Et dans le modèle:
<span>{{your_date | timeAgo}}</span>
Ne réinventez pas la roue, sauf si vous envisagez d'en apprendre davantage sur les roues.
Sur la base de l'excellente réponse de @kemsky, j'ai implémenté une variante de Pipe qui résout quelques problèmes d'implémentation:
Vous pouvez trouver le code complet du tube + les spécifications dans cet article: https://Gist.github.com/JohannesRudolph/8e6de056d9e33353f940d9da9e6ffd82
Je pense que cela n’est pas lié à votre pipe mais à la façon dont Angular2 détecte les changements. Il détecte les modifications en fonction des références, c'est-à-dire si les références liées changent et non si leurs éléments sont mis à jour.
Voir l'exemple suivant:
@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);
}
}
Voir thisx plunkr: https://plnkr.co/edit/kJdi1wx0iu9tDx8yTmRx?p=preview .
A moment.js solution. Travailler/testé dans 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;
}
}
}
Vous devez mettre à jour la référence 'date' pour déclencher la détection de changement d'Angular2, avec un setTimeout(()=>this.date=new Date(), period)
par exemple, comme l'a souligné Thierry.
Avez-vous vraiment besoin d’une mise à jour toutes les secondes? Une mise à jour toutes les 60 secondes peut suffire, selon votre cas d’utilisation, et pourrait afficher «tout à l’heure» ou «il ya moins d’une minute» pendant les 60 premières secondes.
Mais si vous voulez vraiment les secondes, il vous suffit de mettre à jour toutes les secondes pendant les 60 premières secondes. La setTimeout(1000)
peut alors devenir setTimeout(60000)
, afin de minimiser les frais généraux.
Vous devez exécuter cette commande npm time-ago-pipe --save pour installer le paquetage npm time-ago dans votre application angulaire ex: PS D:\D\TimeAgo> npm install time-ago-pipe --save. Après avoir exécuté cette commande, le package sera ajouté. L'image montre comment ajouter une importation {TimeAgoPipe} à partir de 'time-ago-pipe'; dans app.module et mettez TimeAgoPipe dans les déclarations [Transmettre l'entrée du composant o/p