Angular2 + TypeScript + moment.js => locale are not all there (just 'en') - node.js

I am going thru a book tutorial to learn TypeScript and AngularJS 2.0:(Become_a_Ninja_with_Angular2).
At some point it explains how to make your own Pipe and goes thru an implementation of moment.js.
In the folder where my project is located I do in CLI: npm install moment
(FYI: The book also tells to do typings install --save --ambient moment-node, but that throws an error even if I change --ambient by --global, also this error happens to not be a problem to use moment.js as the rest of the code I describe below runs).
Then, as a result of previous CLI, it creates under my project folder: [my project folder]\node_modules\moment
Then in [my project folder]\main.html, I have a <script> tag with: `
<script>
System.config({
defaultJSExtensions: true,
map: {
... [plenty of stuff starting with #angular]..
'#angular/platform-browser-dynamic':'node_modules/#angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'rxjs': 'node_modules/rxjs',
'moment':'node_modules/moment/moment'
}
});
System.import('main');
</script>
My custom Pipe looks like this:
import { PipeTransform, Pipe } from '#angular/core';
import * as moment from 'moment';
import 'moment/../locale/fr';
#Pipe({name: 'fromNow'})
export class FromNowPipe implements PipeTransform {
transform(value,args){
let mydate = moment(new Date(value));
console.log(moment.locales());
return mydate.fromNow();
}
}
As you can see in my custom pipe code, to access the locale 'fr', I had to add import 'moment/../locale/fr (what I found by looking at already existing solution on StackOverflow). If this tag was not implemented I had access to 'en' only. Which means that adding other languages will require to add import 'moment/../locale/[the locale I want available].
Anyone has any ideas how to have all the locale from the lib moment.js with just the single import * as moment from 'moment'; statement?
PS: And I added to [My project folder]\app.module.ts:
import { FromNowPipe } from './custom_pipes/fromnow.pipe';
...
#NgModule({
...
declarations: [...,FromNowPipe],
...
})
...
And somewhere in one of my component I have:
[#Component({
selector: 'ns-mycomponent',
template:`
.. <div>{{ '2016/05/01'|fromNow }}</div>..
`
})

I found a workaround:
Based on what I wrote in the question, in [my project folder]\main.html:
System.config({
defaultJSExtensions: true,
map: {
...
}
});
I substitued: 'moment':'node_modules/moment/moment' with 'moment':'node_modules/moment/min/moment-with-locales.min.js'
In my Pipe file I just kept: import * as moment from 'moment';at the beginning of the file and it works: all languages are available.

Related

Is there a way to abstract the import from a node module using typescript config files in the same style as the 'paths' property?

I am creating private node modules which for now might change considerably in structure which could mean splitting existing code into multiple packages.
If I have 100 files importing from a package that no longer holds the import I can do a find and replace but it becomes more difficult when classes are imported from that package...
so something like:
import { thing1, thing2} from 'my-package';
in the future may need to be:
import { thing1} from 'my-package';
import { thing2} from 'my-package2';
You can abstract imports using tsconfig like so:
"paths": {
"#shared/*": ["app/shared/*"]
}
But I cant figure out a way to do the same thing with node modules so that if there is a bigger change I only need to change 1 line. Is this possible?
Create index.ts file , import and export your modules:
import { assign, assignWith } from 'lodash';
import { addDays } from 'date-fns';
export { assign, assignWith, addDays };
and import modules from that index:
import { assign, addDays } from './index';
Check https://github.com/nrwl/nx
They can help you in using monorepo approach.
You can split your system into Applications and Libraries.

Cannot import AnimeJS in Ionic-Angular project

I have installed AnimeJS with the following commands in my Ionic 4 project:
npm i animejs --save
npm i #types/animejs --save
I then attempted to reference it by using:
import * as anime from 'animejs'
Doing the above gives me the following error when calling anything from animejs:
Error: Uncaught (in promise): TypeError: Object is not a function
(near '...animejs__WEBPACK_IMPORTED_MODULE_1__...')
However, if I import by referencing the anime.js within the node_modules directory, everything will work just as expected. I thought by installing #types/animejs this would allow me to use just a simple import * as anime from 'animejs' without having to directly reference the file within the node_modules directory.
Why can I import using the node_modules folder but not import * as anime from 'animejs'
After importing I call it like so:
openModal(modalPage) {
// Define modal to open
switch (modalPage) {
case 'login' : {
modalPage = LoginPage;
break;
}
case 'register' : {
modalPage = RegisterPage;
break;
}
}
// Open modal
this.modalCtrl.create({
component: modalPage,
cssClass: 'intro-modal',
showBackdrop: true,
enterAnimation: this.animations.modalEnter
}).then(modal => {
// Hide intro buttons
anime({
targets: ['.intro-buttons'],
translateX: '-100%',
duration: 150,
easing: 'linear'
});
// Animate slide back
modal.onWillDismiss().then(() => {
anime({
targets: ['.intro-buttons'],
translateX: '0%',
duration: 150,
easing: 'linear'
});
});
// Present the modal
modal.present();
});
}
Update your import to the following:
import anime from 'animejs'
This will import the default export from animejs which is actually a function that take the params/object that you are attempting to pass.
Here is an example in action showing the import and passing the expected object to anime() without the error triggering.
With your existing import * as anime, if you log anime, you'll see a property default of that object that is the actual function you are needing. Also you will see that import is bringing in various other properties/functions including penner, stagger, and timeline. You were simply targeting the wrong property with your previous import.
Hopefully that helps!

Highlightjs with Angular?

The ng2-smart-table application documentation has code elements snippets that look like this:
<code highlight class="typescript">{{ snippets.require }}</code>
The resulting documentation looks like this.
When looking at the resulting application html, it looks like highlightjs is doing the highlighting, but I don't see an import of an angular dependency that would perform the transform (Or any preprocessing by the scripts), so just wondering how it works?
Per the Answer
Thought is as really cool how simple this is to do with Angular:
import { Directive, ElementRef, AfterViewInit } from '#angular/core';
import * as hljs from 'highlight.js';
#Directive({
selector: 'code[highlight]',
})
export class HighlightCodeDirective implements AfterViewInit {
constructor(private elRef: ElementRef) { }
ngAfterViewInit() {
hljs.highlightBlock(this.elRef.nativeElement);
}
}
Check the code more closely there is a highlight directive (ng2-smart-table/src/app/shared/directives/highlight.directive.ts) that uses highlightjs. It is part of the sample application not the library so you need to copy it if you want to do the same in your application.

Use index.js to import multiple image assets in React

I have been using a pattern of collecting component files for export with index.js files placed in directories, for example:
// index.js file in /components directory
export { Splash } from './Splash'
export { Portfolio } from './Porfolio'
export { Contact } from './Contact'
In Layout.js (located in root directory) I can neatly import with one call:
import { Splash, Portfolio, Contact } from '.'
I use this pattern a lot as I structure components across directories and sub-directories.
My specific question is to ask if there is any way to extend this pattern to image assets collected in src/assets/img? Can I place an index.js file in my images directory and to be able to call groups of images to a component?
//index.js in /src/assets/img directory
export { Img01 } from './img-01.png'
export { Img02 } from './img-02.jpg'
export { Img03 } from './img-03.svg'
//Call in Component.js
import { Img01, Img02, Img03 } from '../assets/img'
I think this should be achievable, but I can't figure out the correct syntax or modifications required to this pattern. Any code samples or recommendations for better practices are appreciated. Thanks in advance!
To export default components do it like this:
export { default as Splash } from './Splash'
export { default as Portfolio } from './Porfolio'
export { default as Contact } from './Contact'
// you dont need to include the 'index' on the route, just do './' if you
// are in the same directory, but your export file must be named index.js
import { Splash, Portfolio, Contact } from './';
To export files: images, css, .svg etc, just include the file extension:
export { default as Img01 } from './img-01.png'
export { default as Img02 } from './img-02.jpg'
export { default as Img03 } from './img-03.svg'
//Call in Component.js
import { Img01, Img02, Img03 } from '../assets/img'
if you are using webpack take a look at this require. You can use require to import a file like the example below:
tree directory
-images
|_index.js
|_notification.png
|_logo.png
-pages
|-home.js
images/index.js
export const notification = require('./notification.png')
export const logo = require('./logo.png')
pages/home.js
import { notification } from '../images/'
<img src={notification} />
i hope i helped you

Create a custom typings file

I just created a published npm package for the first time, called "Foo". I am trying to consume it in a typescript project, but none of the tutorials about how to declare modules with custom typings, are clear to me. Here are the key parts of the npm package:
news.ts
import { tdsRequest } from "../common/request";
function articles(uri) {
return tdsRequest({ method: "GET" }, uri).then(returnData => console.log(returnData, "return data"));
}
export {
articles,
};
main.ts (main export)
import * as news from "./services/news";
export default {
news
};
in the typescript project that's consuming the npm package:
import { news } from "Foo";
and in the typings file ( Foo.d.ts ) I did:
declare module "Foo" {
export {
news: Object,
};
}
I get the following errors: cannot find module news and Cannot export 'Object'. Only local declarations can be exported from a module.
You are mixing default and named exports.
You can do default export style -
main.ts:
import * as news from "./services/news";
export default {
news
};
ts project import:
import foo from "Foo";
const {news} = foo;
foo.d.ts:
declare module "Foo" {
export default {
news: Object,
};
}
Or you can do named exports:
main.ts:
import * as news from "./services/news";
export {
news
};
ts project import:
import {news} from "Foo";
foo.d.ts:
declare module "Foo" {
export const news: Object;
}
But more importantly, you should add declaration: true to your compilerOptions in tsconfig.json in your npm library.
This will generate the d.ts file for you and will save you lots of work. Then, you need to add in package.json a filed called types that will point to the main.d.ts file that will be generated for you. This will allow any project using your library + typescript to use the generated types automatically.

Resources