web-dev-qa-db-fra.com

Pipe angulaire 2 "il y a du temps"

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

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

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.

22
David Prieto

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: 

  • fonctionnera correctement avec angular 2 final et les suivants
  • arrête de voter une fois détruit 
  • utilise un délai d'attente simpliste pour réduire l'intervalle d'interrogation cohérent avec la sortie

Vous pouvez trouver le code complet du tube + les spécifications dans cet article: https://Gist.github.com/JohannesRudolph/8e6de056d9e33353f940d9da9e6ffd82

4
Johannes Rudolph

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 .

0
Thierry Templier

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

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.

0
Julien

Obtenez Time-Ago dans AngularJs2

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

0
Bharath Kalakoti