Master currency-formatting for real-world production applications with this elegant strategy.
JavaScript has grown a lot. Today we use it not only for small business websites, but for complex large-scale applications as well. Sometimes we handle issues that are really important for a business, such as buying or transferring money, and we must think about robust solutions for the long-term.
For those who need to perform currency calculations on the front-end and are struggling with JavaScript floating number precision, I hope this strategy helps you as much as it did me.
You can get the code for this tutorial from the repository below.
github.com/2amigos/vue-currency-filters
Installing Vue.js
If you are already working with Vue.js and you have it installed, skip to the next step “Set up the filters strategy”.
First, using the command line, let’s install the Vue-Cli.
1npm install -g @vue/cli
2# OR
3yarn global add @vue/cli
4
5# Next, create your project.
6
7vue create my-project
You should see a display that looks like the screen shot below.
For the sake of simplicity, I’ll go with default, but you can use the preset you like most or manually select the features you need. Don’t worry. You can also extend the features later.
That’s it! Now you have a fully working Vue.js project with a single command.
Check the documentation for more information about Vue-CLI.
Set up the filters strategy
This is a required step to become a Vue.js master!
Modularization is amazing! Developers have learned that by separating functions in small files, maintenance and testing are easier. This is the next step with filters. You are going to create a file for each “type” of filter you have.
I separated my own filters in three categories — date, string, and currency.
Now, create a filters folder under my-project/src and create a _globals.js file inside.
In the file (_global.js) you will find all the filter files in the directory and add them to Vue.filter. This allows you to use them globally in your app.
Add this code to src/filters/_global.js
1
2import Vue from 'vue';
3
4// Get all the javascript files from the directory where this file is.
5const filters = require.context('.', true, /\.(js)$/i);
6
7// This will be our regular expression to match against the files.
8const nameReg = /([a-z0-9]+)\./i;
9
10filters.keys().forEach((key) => {
11 const name = key.match(nameReg)[1];
12
13 // If the file name is globals we ignore it.
14 if (name === 'globals') return;
15
16 // In case the file only exports one default function we add it to Vue.filter
17 if (filters(key).default) {
18 Vue.filter(key, filters(key).default);
19 } else {
20
21 // We iterate over each export function and add it to Vue.filter
22 Object.keys(filters(key)).forEach((filter) => {
23 if (Object.prototype.hasOwnProperty.call(filters(key), filter)) {
24 Vue.filter(filter, filters(key)[filter]);
25 }
26 });
27 }
28});
29
Finally, to execute this file you need to import it somewhere in your app. The perfect place to do so is your entry file main.js.
1
2import Vue from 'vue'
3import App from './App.vue'
4
5// ‘@’ is an alias for src folder. To know more about webpack alias check this link
6// https://webpack.js.org/configuration/resolve/
7import '@/filters/_globals';
8
9Vue.config.productionTip = false
10
11new Vue({
12 render: h => h(App),
13}).$mount('#app')
14
After adding this code, you can add any file under the filters folder and it will be automatically added to Vue filters.
Install BigNumber and create the currency filters
Now it’s time to add BigNumber.js dependency to your project. Do this by running the next command.
1
2npm install bignumber.js
3# OR
4yarn add bignumber.js
5
Next, create a file under filters folder called currency.js
In this file you can add the filters you want. For example, you might include fiat and cryptocurrency values.
1import { BigNumber } from 'bignumber.js';
2
3// This function creates a bignumber clone with a specific configuration.
4function createBigNumberObject({decimalSeparator = ',', groupSeparator = '.', groupSize = 3} = {}) {
5 return BigNumber.clone({
6 decimalSeparator,
7 groupSeparator,
8 groupSize,
9 });
10}
11
12// Create the big number clones.
13const bnEUR = createBigNumberObject({ decimalSeparator: ',', groupSeparator: '.'});
14
15const bnUSD = createBigNumberObject();
16
17const bnCRYPTO = createBigNumberObject();
18
19// This function accepts a value and a config object and creates a custom formatter
20function createFormatter(value, { bigNumberObject = bnCRYPTO, precision = 2, symbol = null } = {}) {
21 return {
22 format() {
23 const result = bigNumberObject(value).toFormat(precision);
24
25 // If there is a symbol property in the config object we add the symbol at the beginning of the string
26 if (symbol) return result.insert(0, symbol);
27
28 return result;
29 }
30 }
31}
32
33const USD = value => createFormatter(value, { bigNumberObject: bnUSD, symbol: '$'});
34const EUR = value => createFormatter(value, { bigNumberObject: bnEUR, symbol: '€'});
35const CRYPTO = (value, precision = 8) => createFormatter(value, { precision });
36
37// We will access this container objects later on our filter functions
38const CURRENCY_FORMATTER = {
39 USD,
40 EUR,
41};
42const NO_SYMBOL_CURRENCY_FORMATTER = {
43 bnUSD,
44 bnEUR,
45};
46
47// This filter gets the user selected currency and formats your value to match that currency.
48export function currency(value) {
49 // Normally we would use Vuex but for the sake of this example I will use localstorage
50 // to retrieve the user selected currency. Needs to be one of EUR|USD.
51 const userSelectedCurrency = localStorage.getItem('User/selectedCurrency');
52
53 return CURRENCY_FORMATTER[userSelectedCurrency](value).format();
54}
55
56// This filter does the same but returns the formatted value without symbol.
57export function currencyWithoutSymbol(value) {
58 const userSelectedCurrency = localStorage.getItem('User/selectedCurrency');
59
60 return NO_SYMBOL_CURRENCY_FORMATTER[`bn${userSelectedCurrency}`](value).toFormat(2);
61}
62
63// This filter allow you to format a different fiat currency than the one
64// selected by the user.
65export function toCurrency(value, symbol) {
66 return CURRENCY_FORMATTER[symbol](value).format();
67}
68
69// This filter takes a value and optionally adds a symbol and converts the value into
70// crypto currency format
71export function crypto(value, symbol = '') {
72 let precision;
73
74 if (symbol === 'ETH' || symbol === 'ETC') {
75 precision = 16;
76 } else if (symbol === 'XRP') {
77 precision = 6;
78 }
79
80 return CRYPTO(value, precision).format();
81}
82
83// Filter utilities
84export function toFloat(value, places = 2) {
85 return parseFloat(value).toFixed(places);
86}
87
88export function toBigNumber(value) {
89 return new BigNumber(value);
90}
91
92export function bnAbs(bigNumber) {
93 return bigNumber.absoluteValue();
94}
95
96export function bnRemoveTrailingZeros(bigNumber) {
97 return bigNumber.toString();
98}
99
100export function bnToFixed(bigNumber, places = 2) {
101 return bigNumber.toFixed(places);
102}
103
104export function bnMultiply(bigNumber, value) {
105 return bigNumber.multipliedBy(value);
106}
107
108export function bnPlus(bigNumber, value) {
109 return bigNumber.plus(value);
110}
111
112export function bnMinus(bigNumber, value) {
113 return bigNumber.minus(value);
114}
115
Format currencies like a god with filter chaining
Now that you can use your filters everywhere with several useful filters created for currencies, it’s time to use them.
In your template, use the filters like this.
{{ 2.42 | toBigNumber | bnPlus(3) | bnRemoveTrailingZeros }}
Here is an item to consider. If you want to use bigNumber functions like bnPlus, bnMinus, or bnAbs, you need to cast the number to a big number object with the toBigNumber filter.
The bnRemoveTrailingZeros filter is used to call toString() from the big number object.
Summary
You can do powerful things with Vue.js filters. This is one way to take advantage of that power. If you and your team get use to use these filters on your Vue.js single-file-components you can have a standard way of formatting and avoid a lot of small bugs in the future.
Remember you can check the code in this repository, and play around with it.
Accelerate Your Career with 2am.tech
Join our team and collaborate with top tech professionals on cutting-edge projects, shaping the future of software development with your creativity and expertise.
See open positions