How to use moment.js library in angular 2 typescript app?
Asked Answered
B

22

269

I tried to use it with typescript bindings:

npm install moment --save
typings install moment --ambient -- save

test.ts:

import {moment} from 'moment/moment';

And without:

npm install moment --save

test.ts:

var moment = require('moment/moment');

But when I call moment.format(), I get an error. Should be simple, can anybody provide a command line/import combination that would work?

Beaker answered 3/2, 2016 at 0:3 Comment(7)
share your error pleaseEfferent
If I install moment.d.ts and use import, I get compile error ERROR in .../typings/browser/ambient/moment/moment.d.ts (9,21): error TS2503: Cannot find namespace 'moment'. And if I don't install typings and use require, I get Uncaught TypeError: moment.format is not a functionBeaker
There are far too many old answer here. Please look here: github.com/angular/angular-cli/wiki/…Terpsichore
Hinrich's answer worked for me with ng4 (as of June 2017) https://mcmap.net/q/108594/-how-to-use-moment-js-library-in-angular-2-typescript-appLaden
SergeyAldoukhov is this still the best answer? surely @Hinrich's is?Impure
Perfect on angular 7 and moment 2.24.0Clench
For angular 12 I have used #49256540Fixity
S
591

Update April 2017:

As of version 2.13.0, Moment includes a typescript definition file. https://momentjs.com/docs/#/use-it/typescript/

Just install it with npm, in your console type

npm install --save moment

And then in your Angular app, import is as easy as this:

import * as moment from 'moment';

That's it, you get full Typescript support!

Bonus edit: To type a variable or property as Moment in Typescript you can do this e.g.:

let myMoment: moment.Moment = moment("someDate");
Surreptitious answered 6/4, 2017 at 14:21 Comment(11)
is it important to add it to your app.module file and imports array? or can you simply import it within a component and use it?Ardoin
@Katherine R You can use it in any file, it is not Angular specific.Surreptitious
Now, what about moment plugins, like moment-round?Anthropomorphism
Actually this answer is not Angular specific, it applies to any Typescript project.Surreptitious
Great, and how i use pipe on template?Welford
up for bonus edit. was searching for return typings of moment parsesTelamon
any way to avoid the moment.Moment and just use Moment ?Wrinkly
@BrunoSantos can you explain why?Surreptitious
you have to use moment.default() if you are using ES6+ and "allowSyntheticDefaultImports": true in tsconfig.jsonGoing
@Wrinkly You can do this in addition to the above import: import { Moment } from 'moment';. Then you can just use the type directly.Sex
includes 4+mb of source package together for lazy-loaded modules. It slows down the loading time of that moduleUngovernable
R
103

moment is a third party global resource. The moment object lives on window in the browser. Therefor it is not correct to import it in your angular2 application. Instead include the <script> tag in your html that will load the moment.js file.

To make TypeScript happy you can add

declare var moment: any;

at the top of your files where you use it to stop the compilation errors, or you can use

///<reference path="./path/to/moment.d.ts" />

or use tsd to install the moment.d.ts file which TypeScript might find on it's own.

Example

import {Component} from 'angular2/core';
declare var moment: any;

@Component({
    selector: 'example',
    template: '<h1>Today is {{today}}</h1>'
})
export class ExampleComponent{
    today: string = moment().format('D MMM YYYY');
}

Just be sure to add the script tag in your html or moment won't exist.

<script src="node_modules/moment/moment.js" />

Module loading moment

First you would need to setup a module loader such as System.js to load the moment commonjs files

System.config({
    ...
    packages: {
        moment: {
            map: 'node_modules/moment/moment.js',
            type: 'cjs',
            defaultExtension: 'js'
        }
    }
});

Then to import moment into the file where needed use

import * as moment from 'moment';

or

import moment = require('moment');

EDIT:

There are also options with some bundlers such as Webpack or SystemJS builder or Browserify that will keep moment off of the window object. For more information on these, please visit their respective websites for instruction.

Reboant answered 3/2, 2016 at 0:8 Comment(8)
That is possible, but is very lengthy as you would need to have a module loader such as System load in the commonjs node version of moment and then you would be able to reference it with import * as moment from 'moment'; or import moment = require('moment'); which for all intents and purposes are identical, but do have some subtle differences in typescript.Reboant
@Reboant typings install moment --ambient -- save doesn't typings pull down the definition file and create the reference to ///<reference path="./path/to/moment.d.ts" />? I am having the same error when running npm run tscReflate
This is misleading; there's nothing wrong with importing moment.Dichromate
@Dichromate I agree that there is noting wrong with importing moment as a first class import though it would require either a bundling system, or a change in the library. importing won't work out of the box. This is the out-of-the box solution.Reboant
This answer is incomplete because you have to use Typings to manage the moment definition. Also, it doesn't need to import anything. Please, see my answer bellow.Hemimorphic
@BernardoPacheco Agreed. Your answer below shows the global usage case best, and saleksandras' answer shows the most updated way to use moment as a "module".Reboant
This answer is misleading, the fact that moment is a global variable does not mean you "have" to load it as a script tag. You can, and should, bundle it in a vendor file if you are using some sort of bundler (Webpack). You can also workaround the global assignment if you use webpack and a proper loader.Aeromedical
@ShlomiAssaf Added a comment at the bottom of the answer to acknowledge that there are other options. I was simply showing the solution for the option that the OP had chosen.Reboant
D
51

The following worked for me.

First, install the type definitions for moment.

typings install moment --save

(Note: NOT --ambient)

Then, to work around the lack of a proper export:

import * as moment from 'moment';
Dichromate answered 29/3, 2016 at 16:48 Comment(6)
I had to do import moment from "moment"; instead to make it work.Captainship
This answer is incomplete because you don't need to import anything. Please, see my answer bellow.Hemimorphic
Also every iteration of ionic 2 beta / angular 2 rc seemed to bring a new way of importing things so you may have to try a few of these suggestions even though a one point they were once the most up to date answerMarsupium
import * as moment from 'moment'; is the key.Yeta
I'm having Unable to find "moment" ("npm") in the registry. whenI try to install definitions, help pleaseKillian
confusing actually. my old project has import * as moment from 'moment'; but after i created a new angular project and installed moment, that didnt work. what worked was import moment from 'moment';Liliuokalani
S
29

I would go with following:

npm install moment --save

To your systemjs.config.js file's map array add:

'moment': 'node_modules/moment'

to packages array add:

'moment': { defaultExtension: 'js' }

In your component.ts use: import * as moment from 'moment/moment';

and that's it. You can use from your component's class:

today: string = moment().format('D MMM YYYY');

Serra answered 16/5, 2016 at 11:34 Comment(0)
H
25

We're using modules now,

try import {MomentModule} from 'angular2-moment/moment.module';

after npm install angular2-moment

http://ngmodules.org/modules/angular2-moment

Harpole answered 9/10, 2016 at 0:45 Comment(5)
This is insufficient, because this only installs pipes. Apparently, you cannot work with Moment dates in your modules this way.Pumice
would love some tips on how to use angular2-moment filters in the component classReview
this should be: import { MomentModule } from 'angular2-moment/moment.module';Shakeup
This should not be the chosen answer any more. Take a look at @Surreptitious 's answer. npm install moment --save, npm install @types/moment --save #35166668Marinetti
instead of installing a wrapper it should be like import * as moment from 'moment';Airdrome
K
24

To use it in a Typescript project you will need to install moment:

npm install moment --save

After installing moment, you can use it in any .ts file after importing it:

import * as moment from "moment";

Kurman answered 30/11, 2016 at 17:27 Comment(2)
Note** @types/[email protected]: This is a stub types definition for Moment (github.com/moment/moment). Moment provides its own type definitions, so you don't need @types/moment installed!Refine
Great! Here the official reference: momentjs.com/docs/#/use-it/typescriptOverweight
P
24

1: Install moment by command npm install moment --save

2: Do not add anything in the app.module.ts

3: Just add import statement in top of your component or any other file like this: import * as moment from 'moment';

4: Now you can use moment anywhere in your code. Just like:

myDate = moment(someDate).format('MM/DD/YYYY HH:mm');

Pastoral answered 12/1, 2019 at 11:23 Comment(3)
I had to import like this: import * as moment_ from 'moment'; const moment = moment_; Otherwise I was getting Error: Cannot call a namespace ('moment') Omura
Very odd to listen. moment_ is just a literal name. It can be anything, I think...Pastoral
Just be aware that import * as moment from 'moment'; increase the size of the bundle by ~500kb. There is a good article explaining the problem with a solution medium.jonasbandi.net/…Boito
H
15

--- Update 11/01/2017

Typings is now deprecated and it was replaced by npm @types. From now on getting type declarations will require no tools apart from npm. To use Moment you won't need to install the type definitions through @types because Moment already provides its own type definitions.

So, it reduces to just 3 steps:

1 - Install moment which includes the type definitions:

npm install moment --save

2 - Add the script tag in your HTML file:

<script src="node_modules/moment/moment.js" />

3 - Now you can just use it. Period.

today: string = moment().format('D MMM YYYY');

--- Original answer

This can be done in just 3 steps:

1 - Install moment definition - *.d.ts file:

typings install --save --global dt~moment dt~moment-node

2 - Add the script tag in your HTML file:

<script src="node_modules/moment/moment.js" />

3 - Now you can just use it. Period.

today: string = moment().format('D MMM YYYY');
Hemimorphic answered 29/7, 2016 at 17:46 Comment(4)
I'm having trouble with the typings version that is available at dt. It is using an old version of moment that doesn't have the new methods I want to use. If I do as recommended by them (momentjs.com/docs/#/use-it/system-js) the application compiles, but doesn't load in the browser. I'm almost reaching a dead end...Optician
I couldn't get the script tag to work with angular cli. Makes more sense than importing thoughRefine
@Bernardo I tried following your steps and installed moment.js. After declare var moment; However, typings isn't working for me. After typing moment(). no intellisense. I guess I am missing a few steps here.Fillander
Pretty sure this doesn't work, how does web pack know to include this with in the build node modules?Anchovy
D
9

with ng CLI

> npm install moment --save

in app.module

import * as moment from 'moment';

providers: [{ provide: 'moment', useValue: moment }]

in component

constructor(@Inject('moment') private moment)

this way you import moment once

UPDATE Angular => 5

{
   provide: 'moment', useFactory: (): any => moment
}

For me works in prod with aot and also with universal

I dont like using any but using moment.Moment I got

Error   Typescript  Type 'typeof moment' is not assignable to type 'Moment'. Property 'format' is missing in type 'typeof moment'.
Dilatation answered 29/10, 2017 at 20:33 Comment(3)
I get Parameter 'moment' implicitly has an 'any' type error.Brufsky
Does this work for you in prod mode? It was working fine in dev mode, but when I run my app in prod mode it fails. My app has lazy loaded modules too (just in case that matters). moment ends up being null.Covell
@Covell I've tried in a lazy module like constructor( @Inject('moment') private moment) { console.log('date', moment()); } with no problemsDilatation
R
8

The angular2-moment library has pipes like {{myDate | amTimeAgo}} to use in .html files.

Those same pipes can also be accessed as Typescript functions within a component class (.ts) file. First install the library as instructed:

npm install --save angular2-moment

In the node_modules/angular2-moment will now be ".pipe.d.ts" files like calendar.pipe.d.ts, date-format.pipe.d.ts and many more.

Each of those contains the Typescript function name for the equivalent pipe, for example, DateFormatPipe() is the function for amDateFormatPipe.

To use DateFormatPipe in your project, import and add it to your global providers in app.module.ts:

import { DateFormatPipe } from "angular2-moment";
.....
providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}, ...., DateFormatPipe]

Then in any component where you want to use the function, import it on top, inject into the constructor and use:

import { DateFormatPipe } from "angular2-moment";
....
constructor(.......,  public dfp: DateFormatPipe) {
    let raw = new Date(2015, 1, 12);
    this.formattedDate = dfp.transform(raw, 'D MMM YYYY');
}

To use any of the functions follow this process. It would be nice if there was one way to gain access to all the functions, but none of the above solutions worked for me.

Rosauraroscius answered 14/3, 2017 at 15:27 Comment(2)
This is awesome thanks! Everywhere for angular2 moment shows you how to use it on template only. Your very helpful post showed me how to use it to manipulate the value before I output it to the template.Bessel
@Rosauraroscius I see some using the Pipes module and some using just moment to access it in Typescript. I understand you're saying you can use the Pipes version in Typescript but what would the harm be in installing both?Anorthic
S
6

for angular2 RC5 this worked for me...

first install moment via npm

npm install moment --save

Then import moment in the component that you want to use it

import * as moment from 'moment';

lastly configure moment in systemjs.config.js "map" and "packages"

// map tells the System loader where to look for things
  var map = {
  ....
  'moment':                     'node_modules/moment'
  };
  // packages tells the System loader how to load when no filename and/or no extension
  var packages = {
    ...
    'moment':                       { main:'moment', defaultExtension: 'js'}
  };
Subsist answered 31/8, 2016 at 10:13 Comment(3)
Any idea about what is the equivalent step for webpack?Sheelagh
@BharatGeleda No need to do anything with webpack. Using Angular2 and angular-cli I just had to npm install and import it. I didn't need any typings since the last version of moment supports typescript.Chongchoo
The only solution that made me import another locale: import 'moment/locale/de.js'; Thanks!Gastongastralgia
A
5

In addition to SnareChop's answer, I had to change the typings file for momentjs.

In moment-node.d.ts I replaced:

export = moment;

with

export default moment;
Almund answered 17/2, 2016 at 22:59 Comment(0)
M
5

If you're okay adding more third-party packages, I used the angular2-moment library. Installation was pretty straightforward, and you should follow the latest instructions on the README. I also installed typings as a result of this.

Worked like a charm for me, and barely added any code to get it working.

Mithras answered 19/3, 2016 at 0:38 Comment(0)
G
5

Not sure if this is still an issue for people, however... Using SystemJS and MomentJS as library, this solved it for me

/*
 * Import Custom Components
 */
import * as moment from 'moment/moment'; // please use path to moment.js file, extension is set in system.config

// under systemjs, moment is actually exported as the default export, so we account for that
const momentConstructor: (value?: any) => moment.Moment = (<any>moment).default || moment;

Works fine from there for me.

Gem answered 6/6, 2016 at 12:9 Comment(0)
N
5

My own version of using Moment in Angular

npm i moment --save

import * as _moment from 'moment';

...

moment: _moment.Moment = _moment();

constructor() { }

ngOnInit() {

    const unix = this.moment.format('X');
    console.log(unix);    

}

First import moment as _moment, then declare moment variable with type _moment.Moment with an initial value of _moment().

Plain import of moment wont give you any auto completion but if you will declare moment with type Moment interface from _moment namespace from 'moment' package initialized with moment namespace invoked _moment() gives you auto completion of moment's api's.

I think this is the most angular way of using moment without using @types typings or angular providers, if you're looking auto completion for vanilla javascript libraries like moment.

Nonna answered 5/5, 2018 at 7:18 Comment(1)
Installing types will allow you to access the autocomplete: npm install @types/moment --saveMarinetti
I
4

Moment.js now supports TypeScript in v2.14.1.

See: https://github.com/moment/moment/pull/3280

Inmesh answered 8/7, 2016 at 7:18 Comment(0)
D
3

Try adding "allowSyntheticDefaultImports": true to your tsconfig.json.

What does the flag do?

This basically tells the TypeScript compiler that it's okay to use an ES6 import statement, i. e.

import * as moment from 'moment/moment';

on a CommonJS module like Moment.js which doesn't declare a default export. The flag only affects type checking, not the generated code.

It is necessary if you use SystemJS as your module loader. The flag will be automatically turned on if you tell your TS compiler that you use SystemJS:

"module": "system"

This will also remove any errors thrown by IDEs if they are configured to make use of the tsconfig.json.

Dieselelectric answered 27/6, 2016 at 9:53 Comment(0)
C
3

For ANGULAR CLI users

Using external libraries is in the documentation here:

https://github.com/angular/angular-cli/wiki/stories-third-party-lib

Simply install your library via

npm install lib-name --save

and import it in your code. If the library does not include typings, you can install them using:

npm install lib-name --save

npm install @types/lib-name --save-dev

Then open src/tsconfig.app.json and add it to the types array:

"types":[ "lib-name" ]

If the library you added typings for is only to be used on your e2e tests, instead use e2e/tsconfig.e2e.json. The same goes for unit tests and src/tsconfig.spec.json.

If the library doesn't have typings available at @types/, you can still use it by manually adding typings for it:

First, create a typings.d.ts file in your src/ folder.

This file will be automatically included as global type definition. Then, in src/typings.d.ts, add the following code:

declare module 'typeless-package';

Finally, in the component or file that uses the library, add the following code:

import * as typelessPackage from 'typeless-package'; typelessPackage.method();

Done. Note: you might need or find useful to define more typings for the library that you're trying to use.

Cording answered 10/3, 2017 at 16:22 Comment(1)
Checkout this article if you need step-by-step instructions. medium.com/@jek.bao.choo/…Latreshia
R
2

The following worked for me:

typings install dt~moment-node --save --global

The moment-node does not exist in typings repository. You need to redirect to Definitely Typed in order to make it work using the prefix dt.

Respite answered 15/6, 2016 at 11:42 Comment(0)
P
2

for angular2 with systemjs and jspm had to do:

import * as moment_ from 'moment';
export const moment =  moment_["default"];

var a = moment.now();
var b = moment().format('dddd');
var c = moment().startOf('day').fromNow();
Plywood answered 7/9, 2016 at 19:23 Comment(0)
B
1

I followed advice to allow allowSyntheticDefaultImports (since there is no export from moment to use for me), using System. Then I followed someone's advice to use:

import moment from 'moment';

With moment being mapped in my system.js config. The other import statements wouldn't work for me, for some reason

Balk answered 19/8, 2016 at 20:6 Comment(1)
This is the last answer right now, but the only one that's working!Ilise
M
1

With systemjs what I did is, inside my systemjs.config I added map for moment

map: {
   .....,
   'moment': 'node_modules/moment/moment.js',
   .....
}

And then you can easily import moment just by doing

import * as moment from 'moment'
Mitchiner answered 2/11, 2016 at 11:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.