Custom input formatting with simple directives in Angular (2+)
One of the most common requirements that keeps popping up during the development of virtually any kind of application is the ability to use custom format for values in specific input fields.
This translates into a need to display data in a special format which can be quite different from how we represent that data in our model while reverting back to that original representation when editing. For example, let’s say that we have an input that handles money amount with localized decimal and thousand separators.
We can assume that our model stores that amount as number or yet better as string (you know, the floating point math operations in Javascript have tendency to go wrong).
Let’s say that the amount is stored in a standard way such as “100000000.50”. This looks kinda OK, but it is quite hard to see how much that amount actually is without resorting to manually counting the zeros. This can be a tedious and error-prone activity and no user should ever need to deal with these things.
On the other hand, with representation such as “100 ' 000 ' 000 . 50” it becomes rather trivial to get the actual amount the second user lays his eyes on that part of the screen.
Displaying the formatted data
We want to get this functionality for inputs but first, let’s take a step back and think about how do we handle similar, but a bit simpler use-case when we just want to display our formatted value.
Angular 2 got our back because it provide us quite some @ Pipe-s out of the box and an ability to write our own custom pipes by implementing a PipeTransform interface. In our case we will need a currency pipe which may look something like this…
PipeTransform interface contains only the transform method but we also implemented a parse method which reverses the original transformation and will become useful a bit later…
As you may have expected, the pipe is then used simply like…
Unfortunately, we can’t use pipes with inputs in the same fashion.
Formatting the input value
Angular 1.X provided us with mechanism to register new $parsers and $formatters on a ngModel controller which were executed on every model change to achieve the desired effect…
Angular 2 comes with a similar mechanism where we can implement ControlValueAccessor to create our own custom input components as described in a great blog post by Pascal Precht ʕ•̫͡•ʔ, but this can become quite tedious if we need to implement new input component for every custom formatting while we just want them to work with standard text inputs.
But wait, there is a another way !
What we are aiming for is an ability to transparently format values of standard HTML inputs elements with regard to the built in form handling. We want to implement all of our needed formatters and then just decorate appropriate inputs on demand.
This sounds like a case for using a directive and yes, it is ! With the help of Angular 2 @HostListner we can listen to the host input’s events like focus and blur which are perfect match for the described job. Directive also enables us to get reference to the element itself to manipulate it’s value.
Keep in mind that accessing a nativeElement limit’s out possibility to run our Angular 2 application natively on platform others than browser but let’s say we are building primarily a web application
Our input currency formatter directive then can look something like this…
As you can see, we are using previously implemented currency pipe to set input’s value on focus and blur events. Besides that we also want to format the value on initial render which is implemented in ngOnInit() method.
This directive can be used with any kind of text input…
Of course, the template belongs to some of our components which then needs to import and declare our formatter in it’s directive field.
Upcoming Angular 2 release (most probably RC5) will introduce @AppModule which will take on responsibilities of declaring directives and pipes for the components which belong to the particular module, but for the time being we still have to declare our directives on component level
Follow me on Twitter to get notified about the newest blog posts and interesting frontend stuff
Extras
In the example above we used separated [ngModel] and (ngModelChange) bindings to implement one way data flow but this will be a topic of some future blog post — as the tradition goes, the name will most probably be Model pattern for Angular 2 ;)
For now, let’s just check an example implementation of such a component…
Example
Thanks to Martin Dupuis for providing plunker with working example!
Conclusion
As mentioned before, there are multiple ways to implement custom input field value formatting. The most obvious ones are implementing custom input components and implementing formatter directive.
My personal view is that the custom input components can bring more value when implementing truly novel input controls like for example a datepicker with list of predefined values on the side or some crazy slider dropdown combo…
On the other hand, if we are just looking for a way to provide multiple custom formats for standard HTML input elements, the directives look like a more simple and flexible solution…
That’s all for today :)
Please support this article with your 👏 👏 👏 to spread these tips to a wider audience if you found it helpful and follow me on 🕊️ Twitter to get notified about newest blog posts 😉
Also, feel free to check out other interesting front-end related posts like…
Starting an Angular project? Check out Angular NgRx Material Starter!
And never forget, future is bright