Angular 4 tutorial how to create currency directive. Lately, I am studying about angular 4 because there is an ERP project in the company where I work. Creating a currency formatter on the angular is different from the JQuery I’ve discussed in the How to Create Jquery Plugin for Input Currency article. But if you’re used to Angular 4, making currency directive is pretty easy, and the use is more efficient than jquery. Consider the following tutorial.
This simple directive is used to identify input field with the custom currency format. To create a currency format in the input field requires directive and pipe on angular 4. This article will create a custom currency like the following gif image
Before starting the main topic, I will discuss a bit about what is directive and why we need a pipe?
Table of Contents
# Directive
An angular directive is a function executed by Angular when Angular finds Directive in DOM (Document Object Model), the function can almost do everything like hiding element before the page loaded, repeat, execute an expression, etc.
There are two types of directive: built-in directive and custom directive. To create this angular directive in the text field, we need a custom directive.
# Pipe
The pipes are similar to Filters in AngularJs (Angular 1). The pipe is used to format output on HTML templates. Angular 4 also provides built-in pipe such as uppercase, lowercase, currency, Datepipe. In this tutorial, we will create a custom pipe so that the currency format can run well.
Features angular currency input that we will build
- Only number in input typetext
- When element does not get focus/blur, display value in input box will become format currency
- When the element gets the focus, the formatted currency in the text field will disappear
- When the element gets the focus, all the values in the text box will be selected
Tutorial Angular 4 Format Currency In Inputs Value In Angular 4
Note: In the following example I will create a simple directive for Indonesian format currency (Rupiah)
Make a custom directive and a custom pipe
# Custom Pipe
Create a new pipe using an angular-cli with the following command
1 | ng g pipe pipe/mycurrency |
Edit mycurrency.pipe.ts and copy the following code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | import { Pipe, PipeTransform } from '@angular/core'; const padding = "000000"; @Pipe({ name: 'mycurrency' }) export class MycurrencyPipe implements PipeTransform { private prefix: string; private decimal_separator:string; private thousands_separator:string; private suffix:string; constructor(){ this.prefix='Rp.'; this.suffix=''; this.decimal_separator='.'; this.thousands_separator = ','; } transform(value: string, fractionSize:number = 0 ): string { if(parseFloat(value) % 1 != 0) { fractionSize = 2; } let [ integer, fraction = ""] = (parseFloat(value).toString() || "").toString().split("."); fraction = fractionSize > 0 ? this.decimal_separator + (fraction+padding).substring(0, fractionSize) : ""; integer = integer.replace(/\B(?=(\d{3})+(?!\d))/g, this.thousands_separator); if(isNaN(parseFloat(integer))) { integer = "0"; } return this.prefix + integer + fraction + this.suffix; } parse(value: string, fractionSize: number = 2): string { let [ integer, fraction = "" ] = (value || "").replace(this.prefix, "") .replace(this.suffix, "") .split(this.decimal_separator); integer = integer.replace(new RegExp(this.thousands_separator, "g"), ""); fraction = parseInt(fraction, 10) > 0 && fractionSize > 0 ? this.decimal_separator + (fraction + padding).substring(0, fractionSize) : ""; return integer + fraction; } } |
# Custom Directive
Create a new directive using an angular cli with the following command
1 | ng g directive directive/mycurrency |
Edit mycurrency.directive.ts and copy the following code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | import { Directive, HostListener, ElementRef, OnInit } from '@angular/core'; import {MycurrencyPipe} from '../pipe/mycurrency.pipe'; @Directive({ selector: '[appMycurrency]' }) export class MycurrencyDirective implements OnInit{ private el: any; constructor( private elementRef:ElementRef, private formatcurrencypipe:MycurrencyPipe ) { this.el = this.elementRef.nativeElement; } ngOnInit(){ this.el.value = this.formatcurrencypipe.transform(this.el.value); } @HostListener("focus",["$event.target.value","$event"]) onFocus(value,event) { this.el.value = this.formatcurrencypipe.parse(value); // opossite of transform if(event.which== 9) { return false; } this.el.select(); } @HostListener("blur", ["$event.target.value"]) onBlur(value) { this.el.value = this.formatcurrencypipe.transform(value); } @HostListener('keydown', ['$event']) onKeyDown(event) { let e = <KeyboardEvent> event; if ([46, 8, 9, 27, 13, 110, 190].indexOf(e.keyCode) !== -1 || // Allow: Ctrl+A (e.keyCode === 65 && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+C (e.keyCode === 67 && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+V (e.keyCode === 86 && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+X (e.keyCode === 88 && (e.ctrlKey || e.metaKey)) || // Allow: home, end, left, right (e.keyCode >= 35 && e.keyCode <= 39)) { // let it happen, don't do anything return; } // Ensure that it is a number and stop the keypress if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) { e.preventDefault(); } } } |
To use it on the component, please import the pipe first on your component.ts file as shown below
Then open component.html, add appmycurrency as an attribute on the textbox element you want to provide the currency filter
For live demo app
To change the Indonesian format to $ or your country currency change from the mycurrency.pipe.ts in the constructor class
1 2 3 4 5 6 | constructor(){ this.prefix='$'; // change this line with your country this.suffix=''; this.decimal_separator='.'; this.thousands_separator = ','; } |
Read another article: How to Create Autofocus Directive Certain Elements Angular 4
Sigit, the directive doesn’t seem to work if there is a default value in the input text element. By adding [(ngModel)]=”someValue”. If someValue is set in the constructor as this.someValue = 55.8. The expected result should be Rp. 55.80. Is there a way to fix this?
i will fix it ASAP
Thanks you 🙂
I am trying to apply my directive on two binded value using [(ngModel)] and i do not want the value to get carry forwarded to backend. Is there a way to do so while applying this custom directive?
hello Dan, after i check, i try it using formgroup its running well.
Update:
add # decorator below in app.component.html at your input box
Add this code below in yout app.component.ts
Hope fix your problem 🙂
Hi Sigit,
I followed all your steps getting the below error.. can you please let me know how to fix this error?
ERROR Error: StaticInjectorError(AppModule)[MycurrencyDirective -> MycurrencyPipe]:
StaticInjectorError(Platform: core)[MycurrencyDirective -> MycurrencyPipe]:
NullInjectorError: No provider for MycurrencyPipe!
at your component
padding is undefined, what is padding variable for and where are defining it ,
Thanks
Sorry I did not check it and I found padding constant