I'm struggling in using moment.js library inside an Angular 2 Typescript app. Even after reading the answer to this question I can't get it to work.
This is what I did so far:
- I installed moment.js using npm, so I can find the library under node_modules/moment/moment.js
I configured System.js to retrieve moment library:
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
},
moment: {
main: 'moment.js',
type: 'cjs',
defaultExtension: 'js'
}
},
map: {
moment: 'node_modules/moment'
}
});
- I installed typescript typings with
typings install moment-node --ambient --save
and typings install moment --ambient --save
, so I can see the correct typings inside typings/main/ambient/moment-node and typings/main/ambient/moment
Now, if in my code I use import * as moment from 'moment';
typescript compilation run smooth and I can see the correct suggestion inside Atom editor (if I start with moment().
I can see year(), month(), etc.). However if I run my code inside the browser, it gives an error saying that 'moment is not a function' (debugging I can see that moment is an object with lots of methods).
If I write import moment from 'moment';
the code in the browser runs fine, however typescript compilation fails with 'module moment has no default export' and I can't get any suggestion from Atom while writing code.
What am I doing wrong? What's the correct way to import moment.js (and any non typescript library) inside an Angular 2 typescript application?
import * as moment_ from 'moment';
const moment:moment.MomentStatic = (<any>moment_)['default'] || moment_;
As pointed out further down moment ships with its own typings now.
And @angular/cli have changed aswell. Updated my answer to reflect this.
npm i --save moment
import * as moment from 'moment';
export class SomeClass implements OnInit {
date: moment.Moment;
ngOnInit() {
this.date = moment();
}
}
is all that is needed with @angular/cli.
Below is my old outdated answer.
With angular-cli: So you get Intellisense in VsCode
edit --> angular-cli-build.js
module.exports = function(defaults) {
return new Angular2App(defaults, {
vendorNpmFiles: [
...
'moment/min/**', // add this line
...
]
});
};
edit --> system-config.ts
const map: any = {
moment: 'vendor/moment/min/moment.min.js' // add this line
};
In your component:
import * as moment from 'moment';
...
// example of usage
dates: moment.Moment[] = [];
ngOnInit() {
let date = moment();
date.add(2, 'days');
this.dates.push(date);
}
Also I found this:
Install Moment.js using NPM:
npm install moment
Add it to your SystemJS configuration:
map: {
'angular2': 'node_modules/angular2',
'rxjs': 'node_modules/rxjs',
'moment': 'node_modules/moment/moment'
}
You also need the interface:
tsd install moment --save
and then add:
/// <reference path="typings/moment/moment.d.ts" />
import * as moment from 'moment';
From your index.html add
<script src="../node_modules/moment/moment.js"></script>
In your component use:
declare var moment: any;
...
this.startDate = moment().subtract(15, 'days').format('DD-MM-YYYY');
this.endDate = moment().format('DD-MM-YYYY');
When you import a module using namespace syntax to gather the exports onto a single object, as in import * as moment from 'moment'
, you are not importing the actually moment object which the module exports, but rather all of its members. You are losing the call signature. To resolve this, in a SystemJS + TypeScript project, specify either a value of "system" for module or a value of true
for allowSyntheticDefaultImports, passing these to the TypeScript compiler, preferably via a tsconfig.json
file.
Then import moment like so
import moment from 'moment';
and everything will work.