DEV Community

Melvinvmegen
Melvinvmegen

Posted on • Originally published at blog.melvinvmegen.com on

Convert a number to a proper amount in Javascript.

Image description

const amount = (value, currency = "EUR", long) => {
  return (
    (Number(value) || 0)
      .toFixed(long ? 2 : 0)
      .replace(/-/g, "-\u00a0")
      .replace(/(\d)(?=(\d{3})+(\.|$))/g, "$1\u00a0")
      .replace(".", ",") +
    (currency
      ? "\u00a0" +
        ({
          EUR: "",
          USD: "$",
          GBP: "£",
        }[currency] || currency)
      : "")
  );
};
Enter fullscreen mode Exit fullscreen mode

Context

In development we often have to manipulate numbers that need to be represented as amounts to our users. Unfortunately, in javascript there is no native way of doing it.

Well actually there is a native function which as recently been supported in Node 19 thanks to a bump to the latest version of the V8 engine but as we wont be able to use it in production for a while consider this as still relevant :)(Node 19 is a odd numbered release meaning it's not an LTS version, unless it's backported of course).

The amount() function allows us to do it!

Usage

amount(200); // 200 €
amount(200, "$"); // 200 $
amount(200, "GBP"); // 200 £
amount(200, "GBP", true); // 200,00 £
Enter fullscreen mode Exit fullscreen mode

Explanation

The amount() function takes 3 arguments, a number, a currency with a default value of EUR. And last but not least, a boolean conditioning the result as an amount with 2 decimal places or round.

The amount() function then proceeds as follow:

  • The first parameters is either parsed or converted into a Number type thanks to the [Number() function] which is almost equivalent to unary plus (+x) but allows in my opinion for a better understanding. Beware of parseInt() which converts empty strings to NaN. If you're looking for a conversion table.
let value;
value = Number(false) || 0; // 0
value = Number("test") || 0; // 0
value = Number("-1000") || 0; // -1000
Enter fullscreen mode Exit fullscreen mode
  • The value is then converted to a string with the given rounding.
let stringified_value = (Number(1000) || 0).toFixed(0); // '1000'
stringified_value = (Number(1000) || 0).toFixed(2); // '1000.00'
Enter fullscreen mode Exit fullscreen mode
  • In case of a negative number, spaces out the number from the minus in order to properly format it down the line.
const spaced_out_neg_value = stringified_value.replace(/-/g, "-\u00a0"); // '- 1000.00'
Enter fullscreen mode Exit fullscreen mode
  • Properly formatting the value spacing out every third character.
// Space out every third character
const formatted_neg_value = spaced_out_neg_value.replace(
  /(\d)(?=(\d{3})+(\.|$))/g,
  "$1\u00a0"
); // '- 1 000.00'
Enter fullscreen mode Exit fullscreen mode
  • Replaces the dot by a comma the suffix the value with the currency given as second parameter.
const comma_formatted_neg_value = formatted_neg_value.replace(".", ","); // '- 1 000,00'

const currency = "EUR";
const amount =
  comma_formatted_neg_value +
  ("\u00a0" +
    ({
      EUR: "",
      USD: "$",
      GBP: "£",
    }[currency] || currency)); // '- 1 000,00 €'
Enter fullscreen mode Exit fullscreen mode

What if we pass an unreferenced currency? Or if we pass null by accident? Let's try to isolate this behaviour in an independent function.

const add_currency = (value, currency) => {
  return (
    value +
    (currency
      ? "\u00a0" +
        ({
          EUR: "",
          USD: "$",
          GBP: "£",
        }[currency] || currency)
      : "")
  );
};

add_currency("1 000,00", "USD"); // '1 000,00 $'
add_currency("1 000,00", "¥"); // '1 000,00 ¥'
add_currency("1 000,00", "curry"); // '1 000,00 curry'
add_currency("1 000,00", null); // '1 000,00'
Enter fullscreen mode Exit fullscreen mode

As you probably noticed any value can be passed as second parameter but for optimal use it should be added to the values currently supported ({EUR:"€", USD:"$", GBP:"£"})

Conclusion

The final snippet in a concise expression:

const amount = (value, currency = "", long) => {
  return (
    (Number(value) || 0)
      .toFixed(long ? 2 : 0)
      .replace(/-/g, "-\u00a0")
      .replace(/(\d)(?=(\d{3})+(\.|$))/g, "$1\u00a0")
      .replace(".", ",") +
    (currency
      ? "\u00a0" +
        ({
          EUR: "",
          USD: "$",
          GBP: "£",
        }[currency] || currency)
      : "")
  );
};
Enter fullscreen mode Exit fullscreen mode

Top comments (0)