7

As you can read all over the internet using floats to represent currency is a very bad idea. The recommended best practice is to use integers representing cents instead. This way you're safe not to run into any precision problems especially if you're doing some calculations.

As I'm naive and way too optimistic I chose – despite all warning – floats to represent currencies in my app. It went quite well at first. Now I'm running into all kinds of problems (especially with comparison) and want to switch from floats to integers.

Unfortunately angular doesn't support cent integers as an input for the currency filter (at least as far as I know). I'm a bit amazed that it looks like nobody came up with this so far (no corresponding issues on github, nothing on SO etc.).

Are there any best practices? Could you think of any downsides a simple filter like this might have:

angular
    .module('myApp')
    .filter('cents', ['$filter', function($filter) {
        return function(cents, symbol, fractionSize) {
            var asFloat = cents / 100;
            return $filter('currency')(asFloat, symbol, fractionSize);
        };
    }]);
Frederik Kammer
  • 3,117
  • 3
  • 28
  • 29

1 Answers1

2

The downside would probably be the same reason Angular doesn't support throwing cents around in the first place: not all currencies use 100 as their base (Scan down the 'Number to basic' column of that table.)

searlea
  • 8,173
  • 4
  • 34
  • 37
  • Wow, that's a very interesting fact I wasn't aware of! Thank you. But in my opinion that's by far no argument against "throwing cents around". The problem you pointed out could easily be solved by introducing an optional variable (with the default set for all 100 based currencies). I think it really isn't up for debate whether using floats for currency is a good or bad idea. And the advantages of using cents outrage the disadvantages of one further variable by far. – Frederik Kammer Jul 19 '16 at 15:40
  • Out of curiosity: Do you have a link to an actual discussion about this topic? Unfortunately I haven't found anything about why angular doesn't support cent integers. – Frederik Kammer Jul 19 '16 at 15:46
  • No, no link. But note that the currency filter does not accept a currency symbol or any other locale hints, so it does not know what currency your numeric value represents, and therefore can't normalise it. I guess it's probably worth pointing out the standard `Intl.NumberFormat` option available now: `new Intl.NumberFormat(navigator.language, {style:'currency',currency:'EUR'}).format(1234.56)` – searlea Jul 19 '16 at 15:51
  • It does: By default the currency filter uses the $locale service to determine the currency and fraction symbol (see my answer [here](https://stackoverflow.com/questions/27547680/angular-js-currency-symbol-euro-after/34953870#34953870)). And you can specify the symbol as well as the fraction size as a variable (https://docs.angularjs.org/api/ng/filter/currency). So it would be no problem to also specify the factor divided by. – Frederik Kammer Jul 19 '16 at 16:10
  • I meant the currency filter does not have a parameter to identify the currency for _this_ amount (at call-time) allowing you to render different amounts in various currencies correctly without having to know (a) major-to-minor currency-conversion logic, and (b) which currency symbol to display. `Intl.NumberFormat` gets it right with a `currency` parameter taking an ISO currency code. (The angular currency filter was implemented way before `Intl` was finalised...) – searlea Jul 19 '16 at 16:22
  • I guess I'm not really getting your Point. Where is the problem displaying two different currencies correctly with angulars currency filter? Passing another currency symbol does identify the currency for *this* amount. You could easily have `{{ row.price.amount | currency:row.price.symbol }}` inside a `ng-repeat` loop and it would display e.g. euro amounts *and* dollar amounts correctly in the same table. Of course you have to store the information about the currency along with the amount (as you do with `Intl.NumberFormat`) – Frederik Kammer Jul 19 '16 at 17:01
  • My point is that you're **not** identifying the currency, you're passing an arbitrary string to angular's currency filter. It doesn't care if your passing '$' or 'dollaaargh', it'll just blindly render it. There is nothing you can pass to say "I know this is currency X, please render it appropriately" – searlea Jul 19 '16 at 17:18
  • Ah okay, I get it. But it's a bit off topic and doesn't really explain why angular doesn't support cent based integers. Nevertheless an interesting discussion :) BTW: angular2 uses `Intl` for the currency filter (at least internally) – Frederik Kammer Jul 19 '16 at 17:43