How to override the currency symbol used by Intl.NumberFormat - javascript

I am using the Intl.NumberFormat to format currencies on a web page, but I want to use specific currency symbols instead of the locale defined ones.
To be more specific, I want to show C$ for Canadian dollars, instead of the standard $, even though the locale is set to en-CA or fr-CA.
Example:
> Intl.NumberFormat('en-CA', { style: 'currency', currency: 'CAD' }).format(13999.59)
'$13,999.59' // expected 'C$13,999.59'
> Intl.NumberFormat('fr-CA', { style: 'currency', currency: 'CAD' }).format(13999.59)
'13 999,59 $' // expected '13 999,59 C$'
I suppose there is a way to override the currency symbol, but I couldn't find how in the docs.
So, how can I override the currency symbol for a specific locale?

Yes. It is possible with Intl.NumberFormat.prototype.formatToParts() method.
View the documentation here
const enCA = Intl.NumberFormat('en-CA', { style: 'currency', currency: 'CAD' }).formatToParts(13999.59).map(({ type, value }) => {
switch (type) {
case "currency":
return `C$`;
default:
return value;
}
}).reduce((str, pt) => str + pt);
const frCA = Intl.NumberFormat('fr-CA', { style: 'currency', currency: 'CAD' }).formatToParts(13999.59).map(({ type, value }) => {
switch (type) {
case "currency":
return `C$`;
default:
return value;
}
}).reduce((str, pt) => str + pt);
console.log(enCA);
console.log(frCA);

Related

Change the value from string to number and calculate a new result extracting the number with comas and currency(Vuex)

I need to calculate a new number and then extract It with comas and the currency on the Vuex Store... here is the code
export default {
addRegister(state, payload) {
const registerToUpdate = state.registers.find(
(register) => register.id === payload.id
);
const currency = registerToUpdate.currency;
const expenses = registerToUpdate.expense;
//Opcion C (funciona)
let total = registerToUpdate.currentSalar - payload.salary;
if (typeof registerToUpdate.currentSalar === "string") {
parseFloat(registerToUpdate.currentSalar);
total = registerToUpdate.currentSalar - payload.salary;
registerToUpdate.currentSalar = new Intl.NumberFormat("il-IL", {
style: "currency",
currency: currency,
}).format(total);
payload.salary = new Intl.NumberFormat("il-IL", {
style: "currency",
currency: currency,
}).format(payload.salary);
console.log(typeof registerToUpdate.currentSalar, typeof payload.salary);
console.log('total:', registerToUpdate.currentSalar, 'salary: ', payload.salary);
} else {
registerToUpdate.currentSalar = new Intl.NumberFormat("il-IL", {
style: "currency",
currency: currency,
}).format(total);
payload.salary = new Intl.NumberFormat("il-IL", {
style: "currency",
currency: currency,
}).format(payload.salary);
console.log(typeof registerToUpdate.currentSalar, typeof payload.salary);
console.log('total:', registerToUpdate.currentSalar, 'salary: ', payload.salary);
}
expenses.unshift(payload);
},
};
In the first Place on the Vuex store the currentSalar is defined to a Number and after inserting an expense(payload.salary) it's give me the result I want but when I insert a second expense it's give me Nan cause the currentSalar defined to a string.

How to do conditional defining of key in an object in JS?

Suppose I want to create an object with keys as USD and non-USD. Like Below:
let obj = {
USD: {
sourceValue: 100
destinationValue: 10
},
non-USD: {
sourceValue: 10
destinationValue: 100
}
}
Except here, instead of non-USD, I should be able to pass any currency, like SGD or HKD and I should get result of non-USD currency.
so, if I wrote obj[currency].sourceValue and currency=HKD then I should get 10
I don't want to use obj[1].sourceValue as currency value is dynamic.
Also, I don't want to use if(currency!='USD') index=1 and then obj[index].sourceValue
So, my question is, what should I write at place of non-USD while defining object? I checked computation names, but I am not sure, how will I pass long currency array as key name and filter USD out of it?
I don't know of an option in js/ts that would have the key lookup syntax (like obj[currency]) and do the behavior that you want, while keeping the object obj "plain".
But there are options that do what you want with some modifications to the obj and/or with a different call syntax. (The only way that I can think of that would keep the obj completely untouched would require some changes to the currencies then.)
Option 1: add a get function call
const obj1 = {
get: function(currency) {
return this[currency === "USD" ? "USD" : "non-USD"]
},
USD: {
sourceValue: 100,
destinationValue: 10
},
"non-USD": {
sourceValue: 10,
destinationValue: 100
}
}
Or if you cannot change the object's source use Object.assign.
Here you can decide if you want to mutate the original object (Object.assign(target, ...)) or create a new one with Object.assign({}, target, ...)
const addGetter = (target) => Object.assign({}, target, {
get: (currency) => target[currency === "USD" ? "USD" : "non-USD"]
})
const obj1 = addGetter(obj) // <-- pass in the original obj
Usage: obj1.get(currency).sourceValue
Option 2: using a Proxy
Proxy docs, support
Offers the key lookup syntax that you want, but imo, this approach is a bit error-prone, because any access (indexed, by key or property) other than "USD" will return the "non-USD" values. Also the object gets wrapped, which hides object details when logging (console.log(obj)) in some consoles.
const useProxy = (obj) => new Proxy(obj, {
get: (target, currency) => target[currency === "USD" ? "USD" : "non-USD"]
})
const obj2 = useProxy(obj) // <-- pass in the original obj
Usage: obj2[currency].sourceValue
Demo
Check the code comments and the console output
const addGetter = (target) => Object.assign({}, target, {
get: (currency) => target[currency === "USD" ? "USD" : "non-USD"]
})
const useProxy = (obj) => new Proxy(obj, {
get: (target, currency) => target[currency === "USD" ? "USD" : "non-USD"]
})
const obj = {
USD: {
sourceValue: 100,
destinationValue: 10
},
"non-USD": {
sourceValue: 10,
destinationValue: 100
}
}
// Option 1
const obj1 = addGetter(obj)
// Option 2
const obj2 = useProxy(obj)
const c = ["USD", "EUR", "HKD", "non-USD"]
console.log("obj1.get(currency).sourceValue", c.map(currency => currency + " -> " + obj1.get(currency).sourceValue))
console.log("obj2[currency].sourceValue", c.map(currency => currency + " -> " + obj2[currency].sourceValue))
// Option 2 feels a bit error-prone, as any other access will return the fallback value for "non-USD"
console.log("obj2.length", c.map(currency => obj2.length))
console.log("obj2.randomProp", c.map(currency => obj2.randomProp))
You ll actually need to use the if else like condition.
say like this
const key = currency == "USD" ? "USD" : "non-USD";
// and then get the data like this
obj[currency].sourceValue

How to format currency symbol in Intl.NumberFormat?

In a JSON data, I've certain currency data values in the form as follows:
const currencyData = [
{
"₹": "INR"
},
{
"¥": "JPY"
},
{
"€": "EUR"
},
{
"£": "GBP"
}
];
I've created a function which accepts 2 parameters one for 'amount' and other for 'currency code', but, what could be done, when second parameter is "$" or "¥" i.e a currency symbol. My intention is to map the currency symbol with above JSON data and give the relevant output, like for e.g: "$" is passed then it should filter comparing with the above JSON data and pass "USD" output and then it can be passed in the below function
const currencyFormatterNew = (amount, currCode) => {
let currencyCode;
try {
if (currCode == "undefined" || currCode == "") {
currencyCode = "";
} else {
currencyCode = currCode;
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: currencyCode,
minimumFractionDigits: 0
}).format(amount);
}
} catch (err) {
console.log(err);
}
};
The function is called as following: {currencyFormatterNew(10000, "JPY")}
What would be optimal solution to map the 'currency symbol' with above json data and then give required output which could be used in the function created?
Here is the codesandbox link: https://codesandbox.io/s/selection-and-operation-antd-4-17-0-alpha-0-forked-2sqzt
const getCurrencyCode = (code) => {
const k = currencyData.find(a => Object.keys(a) == code);
return Object.entries(k)[0][1];
}
you can try this.
If you want to you can change the last return statement as following
return Object.values(k); // it will return an array
After the JSON has been loaded, store the currencyData array into an object:
const currencyMap = Object.assign({}, ...currencyData)
Then you can just use property accessor [prop] to get the equivalent symbol. This will be better for performance since you don't need to call .find or similar every time your function is called because those functions does a loop.
const currencyData = [
{
"₹": "INR"
},
{
"¥": "JPY"
},
{
"€": "EUR"
},
{
"£": "GBP"
}
];
const currencyMap = Object.assign({}, ...currencyData)
console.log(currencyMap);
let symbol = '₹';
console.log(currencyMap[symbol]);

Decimal/Float input field with locale format

I'd like to solve the following issue:
I got an <input> field that is designed for users to enter decimals like 12.5 in their locale-specific format.
In my case: German locale.
In Germany, we are using a comma as decimal separator.
So the input 12,5 should be computed to a model's value of 12.5.
This is my approach:
<template>
<input
:id="'form-'+name"
v-model="displayValue">
</template>
<script>
export default {
name: 'DecimalField',
props: {
value: [String, Number],
},
data: () => ({
innerValue: '',
}),
watch: {
innerValue (newVal) {
this.$emit ('input', newVal);
},
value (newVal) {
this.innerValue = newVal;
}
},
computed: {
displayValue: {
get: function () {
return Intl.NumberFormat("de-DE",
{ style: "decimal" }).format(this.innerValue);
},
set: function (modifiedValue) {
this.innerValue = Intl.NumberFormat("en-GB",
{ style: "decimal" }).format(modifiedValue);
}
}
},
}
</script>
(You may want to tinker around with this on codepen: https://codepen.io/spqrinc/pen/QWEaYQo ).
** The problem is:**
If you enter 12.5 the value shown in the input is being shown as 12,5 (which is correct in Germany). But if you try to type 12,5, you get NaN.
My question: How can I solve this?

How to insert values into 2d array at specific index using jQuery

I have the following 2 arrays:
groupedObjects: [
{ value: 125, currency: "EUR" },
{ value: 100, currency: "USD" },
{value: 320, currency: "RON" }
]
groupedObjects1: [
{ value: 500, currency: "EUR" },
{ value: 280, currency: "RON" }
]
How can I have those 2 arrays look identical?
I would like that second array, after code looked like:
[
{ value: 500, currency: "EUR" },
{ value: 0, currency: "USD" },
{ value: 280, currency: "RON" }
]
I have tried this code:
if ($(groupedObjects).length > $(groupedObjects1).length) {
_.each(groupedObjects,function(obj){
i++;
_.each(groupedObjects1,function(obj1){
if(obj.currency != obj1.currency) {
alert('Test');
groupedObjects1.push ({
value: '',
currency: ''
});
}
});
});
}
I want that both arrays would be sorted by currency and both of them should have same number of elements, no matter wich array would be larger
groupedObjects= [
{ value: 125, currency: "EUR" },
{ value: 100, currency: "USD" },
{value: 320, currency: "RON" }
];
groupedObjects1= [
{ value: 500, currency: "EUR" },
{ value: 280, currency: "RON" }
];
if ($(groupedObjects).length > $(groupedObjects1).length) {
var newArray = [];
$.each(groupedObjects, function (key, value) {
var flag = false;
var breakout = false;
flag = (function () {
$.each(groupedObjects1, function (key1, value1) {
if (value.currency === value1.currency) {
newArray.push(value1);
breakout = true;
return false;
}
});
if (!breakout) {
return true;
}
})();
if (flag) {
newArray.push({
value: 0,
currency: value.currency
});
}
});
groupedObjects1 = newArray;
}
Well, there are a couple of ways to approach this, and hacking together a function that adds blank values into an array is certainly one of them, but a more object-oriented approach is going to help you a lot more.
I'm not sure how "advanced" you are with javascript, so I'm sorry if it sounds like I'm babying you.
The first thing we want to do is set up a Currency class. There are a few ways to do this, but I prefer the one below, most likely because I'm from a C++ background. Feel free to use another method if you wish.
function Currency(type, quantity){
this.type = type;
this.quantity = quantity;
}
If you want, you could add some validation, such as making sure that quantity is greater than 0 or that type is a valid currency. You could also make those properties private and implement accessors for them, but I'm just trying to keep it simple for now. If you'd like, you could extend it for each currency, so you could say new USD(280) to create a USD object with a value of 280.
So, now that we have our currencies settled, we can think about how we want to store them. We want to make sure that if we haven't added a currency, its quantity is equal to 0. To do this, we'll instantiate an object for each type of currency, then set its value as necessary.
Here's a really simple implementation:
function CurrencyList(){
var valid_currencies = ["EUR", "RON", "USD"];
this.currencies = [];
for(i in valid_currencies){
this.currencies[i] = new Currency(valid_currencies[i], 0);
}
}
I just created an array of valid currencies, iterate through them, and create a "public" property with the valid currency object. I store it in an array like in you have already, it's just in an object.
We're not done yet, though. What if some nefarious person deleted an element in our array? We'd be back to your original problem. We can solve this by making currencies invisible outside the object.
function CurrencyList(){
var valid_currencies = ["EUR", "RON", "USD"];
currencies = [];
for(i in valid_currencies){
currencies[i] = new Currency(valid_currencies[i], 0);
}
}
Now if we try something like this:
var currency_list = new CurrencyList();
alert(currency_list.currencies[0]);
We get an error, which means that our array cannot be modified from outside.
This introduces another problem: what if we want to view an element in our array? The answer is to implement an accessor (a "get") method.
All we have to is create a "public" property and set it equal to a function, like this:
this.at = function(index){
return currencies[index];
}
Now we can access a currency like this:
var currency_list = new CurrencyList();
alert(currency_list.at(0));
This is it all put together:
function CurrencyList(){
var valid_currencies = ["EUR", "RON", "USD"];
currencies = [];
for(i in valid_currencies){
currencies[i] = new Currency(valid_currencies[i], 0);
}
this.at = function(index){
return currencies[index];
}
}
function Currency(type, quantity){
this.type = type;
this.quantity = quantity;
}
This will ensure that you can't have mismatched arrays, so we don't have to bother with a hacky, post hoc solution. In other words, it doesn't solve your problem, but rather prevents the problem from ever existing, which is an even better solution. It also ensures that your array is sorted by currency, because the elements will always be in the order that you specify in your constructor.
Don't use push() Insert de item in the same index.
Use that:
if ($(groupedObjects).length > $(groupedObjects1).length) {
_.each(groupedObjects,function(obj){
i++;
_.each(groupedObjects1,function(index, obj1){
if(obj.currency != obj1.currency) {
alert('Test');
groupedObjects1[index] = ({
value: '',
currency: ''
});
}
});
});
}

Categories

Resources