110

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?

Mridang Agarwalla
  • 43,201
  • 71
  • 221
  • 382
samuel toh
  • 6,836
  • 21
  • 71
  • 108
  • 1
    If you can do it in javascript so you can do it in Vue... use computed properties and return the javascript code. – Happyriri Apr 04 '17 at 13:05

12 Answers12

235

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:

Jess
  • 23,901
  • 21
  • 124
  • 145
  • 5
    My Man! I didn't even know you could do this. Thanks solved my currency problem and cleaned up my mixins since most of them were doing this sort of stuff. – Ominus Feb 18 '18 at 00:33
  • 3
    this is the proper answer – ierdna Oct 20 '18 at 11:40
  • The `Intl` has not the best [support](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Browser_compatibility). – Илья Зеленько Apr 30 '19 at 19:49
  • 2
    How about `isNaN(parseFloat(value))` rather than `typeof value !== "number"`? – RonnyKnoxville May 30 '19 at 11:19
  • @JackalopeZero: Yep, that's a better check. Worked in my case. – dotNET Sep 10 '19 at 05:59
  • 1
    i would change the conditional part, because sometimes the database return string, maybe casting the string to number in that conditional would be better, great answer. – Andres Felipe Oct 04 '19 at 14:45
  • 3
    It's odd that this answer has specified `minimumFractionDigits: 0`. I expect most people wanting to format numbers as currencies will, like me, want to have 2 decimal places displayed, e.g. $5.90, rather than $5.9. In that case you can either specify `minimumFractionDigits: 2`, or indeed just leave that line out altogether since if using `style: 'currency'` it will default to 2 anyway. Hope this helps someone... – Inigo Apr 23 '21 at 19:10
  • @Inigo thank you. I have removed `minimumFractionDigits: 0` as the default will be determined by the type of currency. – Jess Dec 02 '21 at 13:01
  • 1
    Looks like global filters were removed in Vue 3: https://primitive.dev/blog/vue-3-global-filters/ – gabeodess Jul 06 '22 at 22:41
98

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, ',');
});
Emmathem
  • 103
  • 1
  • 1
  • 10
Belmin Bedak
  • 9,011
  • 2
  • 40
  • 44
27

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

Machavity
  • 30,841
  • 27
  • 92
  • 100
Yao Liu
  • 326
  • 3
  • 5
15

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.

Arkowsky
  • 851
  • 7
  • 19
12

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.

AaronBaker
  • 1,013
  • 11
  • 15
8

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.

Andreas Bauer
  • 121
  • 1
  • 5
4

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) }}
Poul Bak
  • 10,450
  • 5
  • 32
  • 57
Rhod
  • 53
  • 4
2

You can use this example

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

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);
      }
    }
  }
Artistan
  • 1,982
  • 22
  • 33
  • 2
    you still could use `val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".")` after that for the . and , changes. – Artistan Jul 19 '17 at 18:22
0

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/

hotcakedev
  • 2,194
  • 1
  • 25
  • 47
0

You can make a filter that works on a project completely. You can also control the number of zeros after the sorter

in main.js create filter like this

Vue.filter("formatNumber", function (value) {
  let val = (value / 1).toFixed(2).replace(".", ",");
  return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
});

<template>
    <div>
        <div class="panel-group"v-for="item in list">
            <div class="col-md-8">
                <small>
                   Total: <b>{{ item.total | formatNumber }}</b>
                </small>
            </div>
        </div>
    </div>
</template>
Esset
  • 916
  • 2
  • 15
  • 17
0

1- you can use following code:

'price'.toString()
      .replace(/\D/g, '')
      .replace(/\B(?=(\d{3})+(?!\d))/g, ',')

2- or just do it using JS methods:

Number('213321333123').toLocaleString('fa-IR') //persian format
Number('213321333123').toLocaleString('en-US') //english format