How do I format currencies in a Vue component?

vue.jsVuejs2Vue ComponentVuex

vue.js Problem Overview


My Vue component is like this :

<template>
    <div>
        <div class="panel-group"v-for="item in list">
            <div class="col-md-8">
                <small>
                   Total: <b>{{ item.total }}</b>
                </small>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        ...
        computed: {
            list: function() {
                return this.$store.state.transaction.list
            },
            ...
        }
    }
</script>

The result of {{ item.total }} is

> 26000000

But I want format it to be like this :

> 26.000.000,00

In jquery or javascript, I can do it

But, How to do it in vue component?

vue.js Solutions


Solution 1 - vue.js

I have created a filter. The filter can be used in any page.

Vue.filter('toCurrency', function (value) {
    if (typeof value !== "number") {
        return value;
    }
    var formatter = new Intl.NumberFormat('en-US', {
        style: 'currency',
        currency: 'USD'
    });
    return formatter.format(value);
});

Then I can use this filter like this:

        <td class="text-right">
            {{ invoice.fees | toCurrency }}
        </td>

I used these related answers to help with the implementation of the filter:

Solution 2 - vue.js

> UPDATE: I suggest using a solution with filters, provided by @Jess.

I would write a method for that, and then where you need to format price you can just put the method in the template and pass value down

methods: {
    formatPrice(value) {
	    let val = (value/1).toFixed(2).replace('.', ',')
	    return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".")
    }
}

And then in template:

<template>
    <div>
        <div class="panel-group"v-for="item in list">
            <div class="col-md-8">
                <small>
                   Total: <b>{{ formatPrice(item.total) }}</b>
                </small>
            </div>
        </div>
    </div>
</template>

BTW - I didn't put too much care on replacing and regular expression. It could be improved. enter code here

Vue.filter('tableCurrency', num => {
  if (!num) {
    return '0.00';
  }
  const number = (num / 1).toFixed(2).replace(',', '.');
  return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
});

Solution 3 - vue.js

With vuejs 2, you could use vue2-filters which does have other goodies as well.

npm install vue2-filters


import Vue from 'vue'
import Vue2Filters from 'vue2-filters'
 
Vue.use(Vue2Filters)

Then use it like so:

{{ amount | currency }} // 12345 => $12,345.00

Ref: https://www.npmjs.com/package/vue2-filters

Solution 4 - vue.js

You can format currency writing your own code but it is just solution for the moment - when your app will grow you can need other currencies.

There is another issue with this:

  1. For EN-us - dolar sign is always before currency - $2.00,
  2. For selected PL you return sign after amount like 2,00 zł.

I think the best option is use complex solution for internationalization e.g. library vue-i18n( http://kazupon.github.io/vue-i18n/).

I use this plugin and I don't have to worry about such a things. Please look at documentation - it is really simple:

http://kazupon.github.io/vue-i18n/guide/number.html

so you just use:

<div id="app">
  <p>{{ $n(100, 'currency') }}</p>
</div>

and set EN-us to get $100.00:

<div id="app">
  <p>$100.00</p>
</div>

or set PL to get 100,00 zł:

<div id="app">
  <p>100,00 zł</p>
</div>

This plugin also provide different features like translations and date formatting.

Solution 5 - vue.js

The comment by @RoyJ has a great suggestion. In the template you can just use built-in localized strings:

<small>
     Total: <b>{{ item.total.toLocaleString() }}</b>
</small>

It's not supported in some of the older browsers, but if you're targeting IE 11 and later, you should be fine.

Solution 6 - vue.js

I used the custom filter solution proposed by @Jess but in my project we are using Vue together with TypeScript. This is how it looks like with TypeScript and class decorators:

import Component from 'vue-class-component';
import { Filter } from 'vue-class-decorator';

@Component
export default class Home extends Vue {

  @Filter('toCurrency')
  private toCurrency(value: number): string {
    if (isNaN(value)) {
        return '';
    }

    var formatter = new Intl.NumberFormat('en-US', {
        style: 'currency',
        currency: 'USD',
        minimumFractionDigits: 0
    });
    return formatter.format(value);
  }
}

In this example the filter can only be used inside the component. I haven't tried to implement it as a global filter, yet.

Solution 7 - vue.js

You can use this example

formatPrice(value) {
  return value.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
},

Solution 8 - vue.js

There is issues with the precision of the accepted answer.

the round(value, decimals) function in this test works. unlike the simple toFixed example.

this is a test of the toFixed vs round method.

http://www.jacklmoore.com/notes/rounding-in-javascript/

  Number.prototype.format = function(n) {
      return this.toFixed(Math.max(0, ~~n));
  };
  function round(value, decimals) {
    return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
  }

  // can anyone tell me why these are equivalent for  50.005, and 1050.005 through 8150.005 (increments of 50)

  var round_to = 2;
  var maxInt = 1500000;
  var equalRound = '<h1>BEGIN HERE</h1><div class="matches">';
  var increment = 50;
  var round_from = 0.005;
  var expected = 0.01;
  var lastWasMatch = true;

  for( var n = 0; n < maxInt; n=n+increment){
    var data = {};
    var numberCheck = parseFloat(n + round_from);
    data.original = numberCheck * 1;
    data.expected =  Number(n + expected) * 1;
    data.formatIt = Number(numberCheck).format(round_to) * 1;
    data.roundIt = round(numberCheck, round_to).toFixed(round_to) * 1;
    data.numberIt = Number(numberCheck).toFixed(round_to) * 1;
    //console.log(data);

    if( data.roundIt !== data.formatIt || data.formatIt !== data.numberIt ||
       data.roundIt !== data.numberIt || data.roundIt != data.expected
      ){
        if(lastWasMatch){
          equalRound = equalRound + '</div><div class="errors"> <hr/> Did Not Round UP <hr/>' ;
            document.write(' <h3>EXAMPLE: Did Not Round UP: ' + numberCheck + '</h3><br /><hr/> ');
            document.write('expected: '+data.expected + ' :: ' + (typeof data.expected)  + '<br />');
            document.write('format: '+data.formatIt + ' :: ' + (typeof data.formatIt)  + '<br />');
            document.write('round : '+data.roundIt + ' :: ' + (typeof data.roundIt)  + '<br />');
            document.write('number: '+data.numberIt + ' :: ' + (typeof data.numberIt)  + '<br />');
            lastWasMatch=false;
        }
        equalRound = equalRound + ', ' + numberCheck;
    } else {
        if(!lastWasMatch){
          equalRound = equalRound + '</div><div class="matches"> <hr/> All Rounded UP! <hr/>' ;
        } {
            lastWasMatch=true;
        }
        equalRound = equalRound + ', ' + numberCheck;
    }
  }
  document.write('equalRound: '+equalRound + '</div><br />');

mixin example

  export default {
    methods: {
      roundFormat: function (value, decimals) {
        return Number(Math.round(value+'e'+decimals)+'e-'+decimals).toFixed(decimals);
      },
      currencyFormat: function (value, decimals, symbol='$') {
        return symbol + this.roundFormat(value,2);
      }
    }
  }

Solution 9 - vue.js

Try this:

methods: {
	formatPrice(value) {
		var formatter = new Intl.NumberFormat('en-US', {
			style: 'currency',
			currency: 'PHP',
			minimumFractionDigits: 2
		});
		return formatter.format(value);
	},
}

Then you can just call this like:

{{ formatPrice(item.total) }}

Solution 10 - vue.js

numeral.js is a JavaScript library for formatting and manipulating numbers.

You can format a currency so easily using it.

For example,

// price = 1200
{numeral(price).format(`$0,0.00`)}

// result $1,200.00

Here's the documentation. http://numeraljs.com/

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionsamuel tohView Question on Stackoverflow
Solution 1 - vue.jsJessView Answer on Stackoverflow
Solution 2 - vue.jsBelmin BedakView Answer on Stackoverflow
Solution 3 - vue.jsYao LiuView Answer on Stackoverflow
Solution 4 - vue.jsArkowskyView Answer on Stackoverflow
Solution 5 - vue.jsAaronBakerView Answer on Stackoverflow
Solution 6 - vue.jsAndreas BauerView Answer on Stackoverflow
Solution 7 - vue.jsMehrab EsmailniaView Answer on Stackoverflow
Solution 8 - vue.jsArtistanView Answer on Stackoverflow
Solution 9 - vue.jsRhodView Answer on Stackoverflow
Solution 10 - vue.jshotcakedevView Answer on Stackoverflow