Giter Club home page Giter Club logo

ngx-timeago's Introduction

ngx-timeago npm version npm License: MIT

Live updating timestamps in Angular 6+.

https://ihym.github.io/ngx-timeago/

Get the complete changelog here: https://github.com/ihym/ngx-timeago/releases

Installation

First you need to install the npm module:

npm install ngx-timeago --save

Choose the version corresponding to your Angular version:

Angular ngx-timeago
16 3.x+
10,11,12,13,14,15 2.x+
6,7,8,9 1.x+

Usage

1. Import the TimeagoModule:

Once installed you need to import the main module into your application module by calling TimeagoModule.forRoot().

Make sure you only call this method in the root module of your application, most of the time called AppModule. This method allows you to configure the TimeagoModule by specifying a formatter, clock and/or an intl service. You should end up with code similar to this:

import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { TimeagoModule } from "ngx-timeago";

@NgModule({
  imports: [BrowserModule, TimeagoModule.forRoot()],
  bootstrap: [AppComponent],
})
export class AppModule {}
SharedModule

If you use a SharedModule that you import in multiple other feature modules, you can export the TimeagoModule to make sure you don't have to import it in every module.

@NgModule({
  exports: [CommonModule, TimeagoModule],
})
export class SharedModule {}
Lazy loaded modules

When you lazy load a module, you should use the forChild static method to import the TimeagoModule.

Since lazy loaded modules use a different injector from the rest of your application, you can configure them separately with a different formatter/clock/intl service.

@NgModule({
  imports: [
    TimeagoModule.forChild({
      formatter: { provide: TimeagoFormatter, useClass: CustomFormatter },
      clock: { provide: TimeagoClock, useClass: CustomClock },
      intl: { provide: TimeagoIntl, useClass: CustomIntl },
    }),
  ],
})
export class LazyLoadedModule {}
I18n

By default, there is no intl service available, as the default formatter doesn't provide language support. You should provide one, if you end up with a formatter that needs it (either TimeagoCustomFormatter which is provided by the lib or your own). The purpose of the intl service is to contain all the necessary i18n strings used by your formatter.

import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { Timeago, TimeagoIntl, TimeagoFormatter, TimeagoCustomFormatter } from "ngx-timeago";
import { AppComponent } from "./app";

export class MyIntl extends TimeagoIntl {
  // do extra stuff here...
}

@NgModule({
  imports: [
    BrowserModule,
    TimeagoModule.forRoot({
      intl: { provide: TimeagoIntl, useClass: MyIntl },
      formatter: { provide: TimeagoFormatter, useClass: TimeagoCustomFormatter },
    }),
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

There is support for a large number of languages out of the box. This support is based on the string objects taken from jquery-timeago.

To use any of the languages provided, you will have to import the language strings and feed them to the intl service.

import { Component } from "@angular/core";
import { TimeagoIntl } from "ngx-timeago";
import { strings as englishStrings } from "ngx-timeago/language-strings/en";

@Component({
  selector: "app",
  template: ` <div timeago [date]="1553683912689"></div> `,
})
export class AppComponent {
  constructor(intl: TimeagoIntl) {
    intl.strings = englishStrings;
    intl.changes.next();
  }
}

You can also customize the language strings or provide your own.

2. Use the pipe or the directive:

This is how you do it with the pipe:

<div>{{1553683912689 | timeago:live}}</div>

And in your component define live (true by default).

This is how you use the directive:

<div timeago [date]="1553683912689" [live]="live"></div>

API

Write your own formatter

If you want to write your own formatter, you need to create a class that implements TimeagoFormatter. The only required method is format that must return the final string.

Example

Once you've defined your formatter, you can provide it in your configuration.

@NgModule({
  imports: [
    BrowserModule,
    TimeagoModule.forRoot({
      formatter: { provide: TimeagoFormatter, useClass: CustomFormatter },
    }),
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

Write your own clock

The only required method to build your own clock, is tick that must return an Observable<any>. Whenever this observable emits, the timestamp will be updated, using your formatter (and intl, if available).

import { TimeagoClock } from "ngx-timeago";
import { Observable, interval } from "rxjs";

// ticks every 2s
export class MyClock extends TimeagoClock {
  tick(then: number): Observable<number> {
    return interval(2000);
  }
}

Setup the clock in your module import by adding it to the forRoot (or forChild) configuration.

@NgModule({
  imports: [
    BrowserModule,
    TimeagoModule.forRoot({
      clock: { provide: TimeagoClock, useClass: MyClock },
    }),
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

Contribute

ngx-timeago is packaged with ng-packagr and then imported into an Angular CLI app. To run the demo, do the following steps:

$ npm install
$ npm run build:lib
$ npm start

MIT © Vasilis Diakomanolis

ngx-timeago's People

Contributors

cyrillbrito avatar frankadrian avatar ihym avatar renovate-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ngx-timeago's Issues

How to use with asynchronously loaded items

When using ngFor with | async loading of items, I get:

ERROR SyntaxError: Wrong parameter in TimeagoPipe. Expected a valid date, received: 1543073998
    at TimeagoPipe.transform (ngx-timeago.js:536)
    at Object.eval [as updateRenderer] (MyComponent.html:40)
    at Object.debugUpdateRenderer [as updateRenderer] (core.js:11080)
    at checkAndUpdateView (core.js:10456)
    at callViewAction (core.js:10692)
    at execEmbeddedViewsAction (core.js:10655)
    at checkAndUpdateView (core.js:10452)
    at callViewAction (core.js:10692)
    at execComponentViewsAction (core.js:10634)
    at checkAndUpdateView (core.js:10457)

When I just use {{ 1543073998 | timeago }} instead of {{ list.date | timeago }}, everything works fine.

Generic type 'ModuleWithProviders<T>' requires 1 type argument(s).

Current behavior

Expected behavior

How do you think that we should fix this?

Minimal reproduction of the problem with instructions

Environment


ngx-timeago version: ^1.0.4
Angular version: 10.0.8


Browser:
- [ ] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
 
For Tooling issues:
- Node version: XX  
- Platform:  

Others:

"The "path" argument must be of type string."

When building app with aot, I'm getting this warning at Ivy compatibility compilation phase.

Warning: Unable to fully load /Users/fxck/www/zeropsmonorepo/node_modules/ngx-timeago/bundles/ngx-timeago.umd.js for source-map flattening: The "path" argument must be of type string. Received type object

Missing null check in pipe: Wrong parameter in TimeagoPipe

Current behavior

Pipe crashes when value is missing

ERROR SyntaxError: Wrong parameter in TimeagoPipe. Expected a valid date, received: null

This will happen while you wait for content to load

{{ item?.createdAt | timeago }}

This will most likely happen during testing, when you don't mock whole object.

Expected behavior

Display nothing

How do you think that we should fix this?

Add null check

Minimal reproduction of the problem with instructions

{{ '' | timeago}}
{{ undefined | timeago}}
{{ null | timeago}}

Environment


ngx-timeago version: ^1.0.4
Angular version: 10.0.12

Output is incorrect

When I enter this pipe {{1549817400 | timeago:live}} it says it was 49 years ago which is incorrect. Can you let me know why it is being outputted this way and how to correct this? It should be 2 days ago.

NullInjectorError: No provider for TimeagoIntl! (Angular 13)

Current behavior

Unable to run the application. Compilation goes fine. But in browser we get a blank page with the following error in console,

main.ts:12 NullInjectorError: R3InjectorError(AppModule)[TimeagoIntl -> TimeagoIntl -> TimeagoIntl]: 
  NullInjectorError: No provider for TimeagoIntl!
    at NullInjector.get (core.mjs:11157:1)
    at R3Injector.get (core.mjs:11324:1)
    at R3Injector.get (core.mjs:11324:1)
    at R3Injector.get (core.mjs:11324:1)
    at NgModuleRef.get (core.mjs:21888:1)
    at Object.get (core.mjs:21565:1)
    at lookupTokenUsingModuleInjector (core.mjs:3367:1)
    at getOrCreateInjectable (core.mjs:3479:1)
    at Module.ɵɵdirectiveInject (core.mjs:14433:1)
    at NodeInjectorFactory.AppComponent_Factory [as factory] (app.component.ts:28:26)

Expected behavior

Application should run without any issues

How do you think that we should fix this?

Minimal reproduction of the problem with instructions

npm install ngx-timeago@latest
npm run start

Environment


ngx-timeago version: 2.0.0
Angular version: 13.3.10


Browser:
- [x] Chrome (desktop) version 102.0.5005.61
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
 
For Tooling issues:
- Node version: v16.13.1  
- Platform:  Mac 

Others:
npm package manager: v8.1.2

Incompatibility with Angular 16

Current behavior

Error: Unexpected value 'TimeagoModule' imported by the module 'AppModule'. Please add an @NgModule annotation.

Expected behavior

Should work

How do you think that we should fix this?

add @NgModule

Support for standalone components

Since Angular 16 many of us are moving to standalone components. Any chance usage without modules could be supported?

In the meantime, this is a solution I used to get it working

main.ts

export const appConfig: ApplicationConfig = {
  providers: [
    ...
    importProvidersFrom(TimeagoModule.forRoot()),
  ],
};

bootstrapApplication(AppComponent, appConfig)...

example.component.ts

@Component({
  standalone: true,
  imports: [CommonModule, TimeagoModule],
  template: `{{ '2023-08-21T14:54:38.342Z' | timeago }}`,
})
export class ExampleComponent { ... }

StackBlitz example

live does not work if date is string

Current behavior

If the date is a string and live is true, the time is not live updated.

Expected behavior

If the date is a string and live is true, the time is live updated.

How do you think that we should fix this?

On this line, use the parsed date instead of the raw input:

this.clockSubscription = this.clock.tick(date)

Minimal reproduction of the problem with instructions

https://stackblitz.com/edit/angular-erlxez

Environment


ngx-timeago version: 1.0.1
Angular version: 8


Browser:
- [x] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
 
For Tooling issues:
- Node version: XX  
- Platform:  

Others:

Broken with Angular 14?

Current behavior

When building the project after upgrading to Angular 14:

./node_modules/ngx-timeago/__ivy_ngcc__/fesm2015/ngx-timeago.js:493:74-110 - Error: export 'ɵɵinjectPipeChangeDetectorRef' (imported as 'ɵngcc0') was not found in '@angular/core'

How do you think that we should fix this?

Not quite sure tbh but I'm assuming there was a breaking change in angular 14 that has to be applied.

Minimal reproduction of the problem with instructions

Add the library (and most likely use the pipe operator) into an angular 14 project.

Environment

ngx-timeago version: 2.0.0
Angular version: 14.1.2
 
For Tooling issues:
- Node version: 16.14.2
- Platform:  Mac

Error with PL intl

image

export interface IL10nsStrings { prefixAgo?: StringOrFn; prefixFromNow?: StringOrFn; suffixAgo?: StringOrFn; suffixFromNow?: StringOrFn; second?: StringOrFn; seconds?: StringOrFn; minute?: StringOrFn; minutes?: StringOrFn; hour?: StringOrFn; hours?: StringOrFn; day?: StringOrFn; days?: StringOrFn; week?: StringOrFn; weeks?: StringOrFn; month?: StringOrFn; months?: StringOrFn; year?: StringOrFn; years?: StringOrFn; wordSeparator?: string; numbers?: NumberArray; }

Interface declare numbers as NumberArray, but pl and other intls dont have it.
Is this because of Intl export or code should handle this without errors?

Feature Request: Allow suffix to be omitted without using a custom formatter

Current behavior

Suffix is always applied via default formatter. e.g.: {{ date | timeago }} => 4 hours ago

Expected behavior

Along the lines of: (first false being the existing 'live' parameter.) e.g.: {{ date | timeago:false:false }} => 4 hours

What is the motivation / use case for changing the behavior?

In some cases (durations, etc) I just want to show the relative time itself and don't want a suffix. e.g.: Active for 4 hours, but don't necessarily want to load a separate library for this.

How do you think that we should implement this?

Optional parameter or other way to omit suffix on a per-use basis.

An hour timestamp only checks once per hour

Current behavior

If I create a timestamp for exactly an hour, the live timeago tick does not fire for an hour, meaning the live updating is not really correct.

Expected behavior

It should probably tick more frequently than every hour if the time is between an hour and a day.

How do you think that we should fix this?

Probably, tick every 5 minutes instead of every hour - that way when it gets into range it will start ticking at a reasonable pace.

Minimal reproduction of the problem with instructions

controller.timestamp = Date.now() + 1000 * 60 * 60;
{{ timestamp | timeago }}

Environment


ngx-timeago version: ^1.0.0
Angular version: 6.0.4

Browser:
- all

angular 6.1.10

Current behavior

Uncaught Error: Template parse errors: The pipe 'timeago' could not be found

Expected behavior

Should work after import

How do you think that we should fix this?

Minimal reproduction of the problem with instructions

npm install ngx-timeago --save
..then add:

import {TimeagoModule} from "ngx-timeago";
@NgModule({
imports: [
    TimeagoModule.forRoot()

then try use in code.

Environment


ngx-timeago version: ^1.0.1
Angular version: 6.1.10

Cannot set property 'strings' of undefined

I got this error "Cannot set property 'strings' of undefined" when i change the language format on my contructor

import { TimeagoIntl } from 'ngx-timeago';
import { strings as englishShortStrings } from 'ngx-timeago/language-strings/en-short';
constructor(intl: TimeagoIntl) {
intl.strings = englishShortStrings;
intl.changes.next();
}

If anyone know how to fix this problem please help!
Cordialy

Angular 17 support

Hi there,
Will you guys be able to update this package to support Angular 17?
Thank!

:live not required

Hi,

I like this package, but it looks like the readme is wrong/outdated.
When adding the component like this: {{lastUpdate | timeago:live}} it works on my local machine.
However docker.com failed with the following error:

Property 'live' does not exist on type 'ButtonComponent'

After removing the :live {{lastUpdate | timeago}} it still worked and time increased as expected.
Is this behaviour changed? Or am I missing something?

Production build breaks internationalization strings

Expected behaviour

When doing ng build --prod with the custom formatter times show up as less than a minute ago

Actual behaviour

Instead of less than a minute ago it shows n second and instead of n minutes ago shows n minute

Component:

  constructor(private store: AngularFirestore, private intl: TimeagoIntl) {}

  ngOnInit(): void {
    // This is to hide a warning until a new version of Firebase package comes
    this.store.firestore.settings({timestampsInSnapshots: true});

    this.setClockInternationalization();
    this.fetchResources();
  }

  private setClockInternationalization(): void {
    this.intl.strings = englishStrings;
    this.intl.changes.next();
  }

Module:

@NgModule({
  imports: [
    AngularFirestoreModule,
    AvatarModule,
    CommonModule,
    MatButtonModule,
    MatProgressBarModule,
    MatTableModule,
    TimeagoModule.forRoot({
      clock: {provide: TimeagoClock, useClass: SlowUpdatingClock},
      formatter: {provide: TimeagoFormatter, useClass: TimeagoCustomFormatter},
    }),
  ],
  providers: [TimeagoIntl],
})

I'm sure it's an easy fix, great work though!

Support for Angular 13

Current behavior

When going from Angular 12 to 13, my tests started showing this error:

Importing TimeagoModule which does not have a ɵmod property

Expected behavior

ngx-timeago should be Ivy compatible.

What is the motivation / use case for changing the behavior?

I'd like to upgrade to Angular 13 but I'm blocked by this.

Pipe Internationalization not working

Current behavior

Internationalization does not work

Expected behavior

Internationalization does work :)

Minimal reproduction of the problem with instructions

  • Follow the Readme to setup Internationalization
  • ... String will still show up as English

Reproduction at https://stackblitz.com/edit/angular-6hhf8a

Environment

ngx-timeago version: 1.0.2
Angular version: 6.0.0, 8.0.0, 8.2.2

Browser:

  • all

Docs claim format is the only required method on the custom formatter

Current behavior

Readme states as follows:

Write your own formatter
If you want to write your own formatter, you need to create a class that implements TimeagoFormatter. The only required method is format that must return the final string.

Expected behavior

The above is not true, TS requires also parse method to be extended.

How do you think that we should fix this?

Minimal reproduction of the problem with instructions

Try not to provide parse in your custom formatter.
https://stackblitz.com/edit/angular-7avyzw?file=src%2Fapp%2Fapp.module.ts

Environment


ngx-timeago version: 1.0.0
Angular version: 7.x

I would suggest to either make the parse method indeed not required, or export the internal default one.

transform method in timeago.pipe.ts should take an "any" instead of a "number" as input type

Current behavior

When creating an Angular library with a component using ngx-timeago, then compiling this project fails due to the fact that our model uses a Date type instead of a number.
Where normal usage (passing a string, a date or a number) works fine when you use ngx-timeago immediately in your project, it does not work when using an angular library. It seems that the type checking is more strict compared to normal usage (even with --aot)

ngx-timeago is added to the module and also exported from the module.

simplified model:
export class Model { lastModified: Date; }

Html:
<p class="modified">{{ item.lastModified | timeago }}</p>

The above code gives the following exception when running ng-packagr:

Building Angular Package
Building entry point ''
Compiling TypeScript sources through ngc
Browserslist: caniuse-lite is outdated. Please run next command npm update caniuse-lite browserslist

BUILD ERROR
projects\shared-lib\src\lib\components\my-component\my-component.component.html(24,68): : Argument of type 'string | Date' is not assignable to parameter of type 'number'.
Type 'string' is not assignable to type 'number'.

Error: projects\shared-lib\src\lib\components\my-component\my-component.component.html(24,68): : Argument of type 'string | Date' is not assignable to parameter of type 'number'.
Type 'string' is not assignable to type 'number'.

at Object.<anonymous> (C:\_src\Shared\node_modules\ng-packagr\lib\ngc\compile-source-files.js:40:68)
at Generator.next (<anonymous>)
at C:\_src\Shared\node_modules\ng-packagr\lib\ngc\compile-source-files.js:7:71
at new Promise (<anonymous>)
at __awaiter (C:\_src\Shared\node_modules\ng-packagr\lib\ngc\compile-source-files.js:3:12)
at Object.compileSourceFiles (C:\_src\Shared\node_modules\ng-packagr\lib\ngc\compile-source-files.js:17:12)
at Object.<anonymous> (C:\_src\Shared\node_modules\ng-packagr\lib\ng-v5\entry-point\ts\compile-ngc.transform.js:31:32)
at Generator.next (<anonymous>)
at C:\_src\Shared\node_modules\ng-packagr\lib\ng-v5\entry-point\ts\compile-ngc.transform.js:7:71
at new Promise (<anonymous>)

Expected behavior

The compilation should succeed when passing valid values from Date type and string.

How do you think that we should fix this?

The timeago pipe should take in an object of type "number | date | string" since it parses all of those to a date, or it could even be an any since it tries to parse anything to a date anyway.

Minimal reproduction of the problem with instructions

Steps to reproduce:

  1. Create an angular library project
  2. Add ngx-timeago to the project and export is
  3. Add a component to the project and export it
  4. Build the library project ==> error occurs

Environment


ngx-timeago version: 1.0.3
Angular version: 7.2.0


Browser: no browser, during compilation

For Tooling issues:
- Node version: 10.18.0 XX 
- Platform:  Windows

Others:

TimeAgo pipe does not work with SSR

Probably due to resolving an observable, but TimeAgo only works on the browser. If implemented with SSR, SSR hangs and the page never loads.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.