Removing AngularJS currency filter decimal/cents - angularjs

Is there a way to remove the decimal/cents from the output of a currency filter? I'm doing something like this:
<div>{{Price | currency}}</div>
Which outputs:
$1,000.00
Instead, I'd like:
$1,000
Can that be done using the currency filter? I know I can prepend a dollar sign onto a number, and I could write my own filter, but I was hoping a simple method exists with the existing currency filter.
Thank you.

Update: as of version 1.3.0 - currencyFilter: add fractionSize as optional parameter, see commit
and updated plunker
{{10 | currency:undefined:0}}
Note that it's the second parameter so you need to pass in undefined to use the current locale currency symbol
Update: Take note that this only works for currency symbols that are displayed before the number.
As of version 1.2.9 it's still hardcoded to 2 decimal places.
Here is a modified version that uses a copy of angular's formatNumber to enable 0 fractionSize for currency.
Normally this should be configurable either in the locale definition or the currencyFilter call but right now(1.0.4) it's hardcoded to 2 decimal places.
Custom filter:
myModule.filter('noFractionCurrency',
[ '$filter', '$locale',
function(filter, locale) {
var currencyFilter = filter('currency');
var formats = locale.NUMBER_FORMATS;
return function(amount, currencySymbol) {
var value = currencyFilter(amount, currencySymbol);
var sep = value.indexOf(formats.DECIMAL_SEP);
if(amount >= 0) {
return value.substring(0, sep);
}
return value.substring(0, sep) + ')';
};
} ]);
Template:
<div>{{Price | noFractionCurrency}}</div>
Example:
Demo
Update: fixed a bug when handling negative values

The question seems to be pretty old and the given answers are nice. However, there is another alternative solution which can also help (which I use in my projects).
This is working very well with currency symbols prefixing as well as suffixing the number for positive and negative values.
Custom filter:
angular.module('your-module', [])
.filter('nfcurrency', [ '$filter', '$locale', function ($filter, $locale) {
var currency = $filter('currency'), formats = $locale.NUMBER_FORMATS;
return function (amount, symbol) {
var value = currency(amount, symbol);
return value.replace(new RegExp('\\' + formats.DECIMAL_SEP + '\\d{2}'), '')
}
}])
Template:
<div>{{yourPrice| nfcurrency}}</div>
Examples for different locales:
10.00 (en-gb) -> £10
20.00 (en-us) -> $20
-10.00 (en-us) -> ($10)
30.00 (da-dk) -> 30 kr
-30.00 (da-dk) -> -30 kr
Please have a look at live demo for US dollars and Danish Krone.
Update
Please note that this workaround is good for AngularJS 1.2 and earlier releases of the library. As of AngularJS 1.3 you can use currency formatter with third parameter specifying fraction size - "Number of decimal places to round the amount to".
Note that in order to use default currency format coming from AngularJS localization, you would have to use currency symbol (second parameter) set to undefined (null or empty will NOT work). Example in demos for US dollars and Danish Krone.

Another thing that is worth considering is if you know you only have one locale or one type of currency, you could put the currency symbol before the number and then use the number filter like so (for US currency).
${{Price | number:0}}
More of a quick fix solution if you don't want to throw in a new filter and only have one currency.

It's late but might be it can help some one
{{value | currency : 'Your Symbol' : decimal points}}
So let's see some examples with output
{{10000 | currency : "" : 0}} // 10,000
{{10000 | currency : '$' : 0}} // $10,000
{{10000 | currency : '$' : 2}} // $10,000.00
{{10000 | currency : 'Rs.' : 2}} // Rs.10,000.00
{{10000 | currency : 'USD $' : 2}} // USD $10,000.00
{{10000 | currency : '#' : 3}} // #10,000.000
{{10000 | currency : 'ANYTHING: ' : 5}} // ANYTHING: 10,000.00000
See the demo

This is another similar solution, but it removes .00 decimal, but leaves any other decimal amount.
$10.00 to $10
$10.20 to $10.20
app.filter('noFractionCurrency', [ '$filter', '$locale', function(filter, locale) {
var currencyFilter = filter('currency');
var formats = locale.NUMBER_FORMATS;
return function(amount, currencySymbol) {
amount = amount ? (amount*1).toFixed(2) : 0.00;
var value = currencyFilter(amount, currencySymbol);
// split into parts
var parts = value.split(formats.DECIMAL_SEP);
var dollar = parts[0];
var cents = parts[1] || '00';
cents = cents.substring(0,2)=='00' ? cents.substring(2) : '.'+cents; // remove "00" cent amount
return dollar + cents;
};
}]);

Solution for angular version < 1.3,
if you use i18n the simplest way is:
$filter('number')(x,0) + ' ' +$locale.NUMBER_FORMATS.CURRENCY_SYM;
This way you have the number formatted with correct separators and currency symbol based on locale.

Another solution, this one removes the trailing zeros and finds the proper currency symbol for the most common currencies:
{{10.00|money:USD}} to $10
{{10.00|money:EUR}} to €10
/**
* #ngdoc filter
* #name money
* #kind function
*
* #description
* Formats a number as a currency (ie $1,234.56), removing trailing zeros and using the real currency symbol when possible. When no currency symbol is provided, default
* symbol for current locale is used.
*
* #param {number} amount Input to filter.
* #param {string=} symbol Currency symbol or identifier to be displayed.
* #returns {string} Formatted number. *
*/
app.filter('money', [ '$filter', '$locale', function (filter, locale) {
var currencyFilter = filter('currency');
var formats = locale.NUMBER_FORMATS;
var getCurrencySymbol = function (code) {
switch (code.toUpperCase()) {
case 'EUR': //Euro
return '€';
case 'USD': //Dólar americano
case 'MXN': //Peso mejicano
case 'CAD': //Dólar de Canadá
case 'AUD': //Dólar australiano
case 'NZD': //Dólar neozelandés
case 'HKD': //Dólar de Hong Kong
case 'SGD': //Dólar de Singapur
case 'ARS': //Peso argentino
return '$';
case 'CNY': //Yuan chino
case 'JPY': //Yen japonés
return '¥';
case 'GBP': //Libra esterlina
case 'GIP': //Libras de Gibraltar
return '£';
case 'BRL': //Real brasileño
return 'R$';
case 'INR': //Rupia india
return 'Rp';
case 'CHF': //Franco suizo
return 'Fr';
case 'SEK': //Corona sueca
case 'NOK': //Corona noruega
return 'kr';
case 'KPW': //Won de Corea del Norte
case 'KRW': //Won de Corea del Sur
return '₩';
default:
return code;
}
};
return function (amount, currency) {
var value;
if (currency) {
value = currencyFilter(amount, getCurrencySymbol(currency));
}
else {
value = currencyFilter(amount);
}
//Remove trailing zeros
var regex = new RegExp("\\" + formats.DECIMAL_SEP + "0+", "i");
return value.replace(regex, '');
};
} ]);

And here if you want to round up to nearest $1000: Live Demo:
var app = angular.module('angularjs-starter', []);
app.filter('noFractionRoundUpCurrency',
[ '$filter', '$locale', function(filter, locale) {
var currencyFilter = filter('currency');
var formats = locale.NUMBER_FORMATS;
return function(amount, currencySymbol) {
var value = currencyFilter(amount, currencySymbol);
var sep = value.indexOf(formats.DECIMAL_SEP);
if(amount >= 0) {
if (amount % 1000 < 500){
return '$' + (amount - (amount % 500));
} else {
return '$' + (amount - (amount % 500) + 500);
}
}
else{
if (-amount % 1000 < 500){
return '($' + (-amount - (-amount % 500)) + ')';
} else {
return '($' + (-amount - (-amount % 500) + 500)+ ')';
}
}
};
} ]);
app.controller('MainCtrl', function($scope) {
});

Exactly what I needed!
I added a conditional to just replace Angular's currency filter altogether and just use a modified version of the filter seen above by #Tom. I'm sure there are better ways to do this but it seems to work well for me thus far.
'use strict';
angular.module('your-module')
.filter('nfcurrency', [ '$filter', '$locale', function ($filter, $locale) {
var currency = $filter('currency'), formats = $locale.NUMBER_FORMATS;
return function (amount, symbol) {
var value = currency(amount, symbol), valArr = value.split(formats.DECIMAL_SEP);
if(parseInt(valArr[(valArr.length - 1)]) > 0) {
return value;
} else {
return value.replace(new RegExp('\' + formats.DECIMAL_SEP + '\d{2}'), '');
}
};
}]);

I have modified a bit the filter posted by #Liviu T. to accept currencies with symbol after the number and certain number of decimals:
app.filter('noFractionCurrency',
[ '$filter', '$locale', function(filter, locale) {
var currencyFilter = filter('currency');
var formats = locale.NUMBER_FORMATS;
return function(amount, num, currencySymbol) {
if (num===0) num = -1;
var value = currencyFilter(amount, currencySymbol);
var sep = value.indexOf(formats.DECIMAL_SEP)+1;
var symbol = '';
if (sep<value.indexOf(formats.CURRENCY_SYM)) symbol = ' '+formats.CURRENCY_SYM;
return value.substring(0, sep+num)+symbol;
};
} ]);
For example:
{{10.234 | noFractionCurrency:0}}
{{10.55555 | noFractionCurrency:2}}
Outputs:
$10
$10.56
Demo

If you'd use angular-i18n (bower install angular-i18n), you could use a decorator to change the defaults in the locale files, like so:
$provide.decorator('$locale', ['$delegate',
function ($delegate) {
$delegate.NUMBER_FORMATS.PATTERNS[1].maxFrac = 0;
$delegate.NUMBER_FORMATS.PATTERNS[1].minFrac = 0;
return $delegate;
}]);
Note that this would apply to all currency filter uses in your code.

In Angular 4+
{{totalCost | currency : 'USD' : 'symbol' : '1.0-0' }}

Related

Angular JS currency filter showing same format for ₹ and $

I have a scenario where i should be able to format the currency dynamically. I'm using angular currency filter.
Here is my code
<div ng-app="myApp" ng-controller="costCtrl">
<p>Rupee: {{ price | currency : "₹"}}</p>
<p>Dollar: {{ price | currency : "$"}}</p>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('costCtrl', function($scope) {
$scope.price = 5800000;
});
In the above code i'm using two types of currencies RUPEE and DOLLAR but it is showing same for the both currencies.
here is my output for above code
RUPEE : ₹5,800,000
DOLLAR: $5,800,000
below is my expected output
RUPEE : ₹58,00,000
DOLLAR: $5,800,000
please help me in this. Thanks in advance
I need a generic solution for all currency formats not only for indian rupee. Like €1.234.567,89 EUR
Here EUR currency format is different they use . as thousand separators and , as decimal separators.
Can i have any suggestions for implementing this.
You have to write your own currency convertor, below is a working fiddle:
.filter('currency', function() {
var defaultCurrency = '$';
return function(input, currencySymbol) {
var out = "";
currencySymbol = currencySymbol || defaultCurrency;
switch(currencySymbol) {
case '₹':
out = 67 * input;
break;
default:
out = input;
}
return out + ' ' + currencySymbol;
}
});
http://jsfiddle.net/bvgkwczd/

How to sort results after I filtered them with angular

I have a table and each row has a column with an amount of money. That amount can be in different currency. For now I have two different currencies, for example euros and dollars.
In order to sort that table by amount of money (low-to-high or reverse) I should first convert the amount in dollars for example and then sort the table.
So, I have an order function that works well reference : https://docs.angularjs.org/api/ng/filter/orderBy
I created a filter 'currency' that converts the amount from euros to dollars (i have this as default). The currency converter works good.
But, when I click the button for ordering, I see the results with the converted currency but the table is ordered with the numeric value of the first results.
ng-click="changeCurrencyToDollars(); order('bonus_amount');"
For example the initial data is :
10 US Dollar
9 Euros
and it is converted to :
US Dollar
11.14 US Dollar
Any ideas why the sorting is not working on the converted currency (filtered results) ?
Thanks
Controller:
$scope.convertedCurrency = false; //initial table data with mixed currencies
$scope.changeCurrencyToDollars = function (){
$scope.convertedCurrency = $scope.convertedCurrency ? false: true;
};
$scope.order = function(predicate){
$scope.predicate = predicate;
$scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
$scope.operators = orderBy($scope.operators, predicate, $scope.reverse);
};
app.filter('currency', [function() {
var defaultCurrency = 'Dollars';
return function(input, currencySymbol){
var out = "";
currencySymbol = currencySymbol || defaultCurrency;
switch (currencySymbol){
case 'Dollars':
out = input;
break;
case 'EUR':
out = 1.11 * input; // convert to dollars
currencySymbol = defaultCurrency;
break;
default:
out = input;
}
return out.toFixed(0) + ' ' + currencySymbol;
}
}]);
View:
Inside the ng-repeat:
<span class="highlight-word" ng-if="!convertedCurrency">{{operators.bonus_amount}} {{operators.bonus_currency}}</span>
<span class="highlight-word" ng-if="convertedCurrency">{{operators.bonus_amount | currency: operators.bonus_currency}}</span>
How I solved it:
I inserted a new property to every object with the converted value. That way every object had a "dollars" property. And for sorting I used the same $scope.order, since it was working but with the new property of the object. Not the best angular solution, but at least the "weight" was in the controller and not in the view.
you have not given your object but ,let's say that is it like this:
$scope.operator = [{
bonus_amount:'100',
bonus_currency:'Dollars'},
{
bonus_amount:'10',
bonus_currency:'Dollars'},
{
bonus_amount:'150',
bonus_currency:'Dollars'}];
Now let's add the currency filter(you put your custom filter to make the conversion) and the orderby filter, and show the data:
In your ng-repeat you add the 'orderBy' filter and then, when you show the data you add the 'currency' filter:
<li ng-repeat="operators in operator | orderBy:'+bonus_amount'">{{operators.bonus_amount | currency }}</li>
Hope helps, good luck.

Convert birthday to age in angularjs

I want to display age of all my users to grid. I am reading data from facebook.I am not storing it at anywhere.
i am displaying date like :
{{ friend.birthday }}
How can i display age instead of displaying birthday.
if it is possible to create filters than how to create filter and how to apply it.
You can implement a function:
Controller:
$scope.calculateAge = function calculateAge(birthday) { // birthday is a date
var ageDifMs = Date.now() - birthday.getTime();
var ageDate = new Date(ageDifMs); // miliseconds from epoch
return Math.abs(ageDate.getUTCFullYear() - 1970);
}
HTML
{{ calculateAge(friend.birthday) }}
Or a filter:
app.filter('ageFilter', function() {
function calculateAge(birthday) { // birthday is a date
var ageDifMs = Date.now() - birthday.getTime();
var ageDate = new Date(ageDifMs); // miliseconds from epoch
return Math.abs(ageDate.getUTCFullYear() - 1970);
}
return function(birthdate) {
return calculateAge(birthdate);
};
});
HTML
{{ friend.birthday | ageFilter }}
Age algorithm taken from this SO answer.
[EDIT] If the age is less than 1 year, and you want to show months, you can modify the ageFilter to calculate the month difference:
app.filter('ageFilter', function() {
function calculateAge(birthday) { // birthday is a date
var ageDifMs = Date.now() - birthday.getTime();
var ageDate = new Date(ageDifMs); // miliseconds from epoch
return Math.abs(ageDate.getUTCFullYear() - 1970);
}
function monthDiff(d1, d2) {
if (d1 < d2){
var months = d2.getMonth() - d1.getMonth();
return months <= 0 ? 0 : months;
}
return 0;
}
return function(birthdate) {
var age = calculateAge(birthdate);
if (age == 0)
return monthDiff(birthdate, new Date()) + ' months';
return age;
};
});
Demo Plunker - Age Function
Demo Plunker - Age Filter
Demo Plunker - Age Filter with Months < 1 year
If you're value is just for example "05/01/2016". This will be a useful code to convert the date to birthday.
AngularJS
app.filter('ageFilter', function(){
return function(birthday){
var birthday = new Date(birthday);
var today = new Date();
var age = ((today - birthday) / (31557600000));
var age = Math.floor( age );
return age;
}
});
HTML
{{ relationTypePreDefined.birthdate | ageFilter }}
By the way I used this solution to convert a date coming from a jquery datepicker input to age.
If you are using momentjs. Then you can create filter simply by using this snippet
var now = "04/09/2013 15:00:00";
var then = "04/09/2013 14:20:30";
moment.utc(moment(now,"DD/MM/YYYY HH:mm:ss").diff(moment(then,"DD/MM/YYYY HH:mm:ss"))).format("HH:mm:ss")
Idk why I can never reply to people, says I need more rep but to rep I need to comment.. whatever.
In response to #Dean Christian Armada's, I kept getting an error regarding the filter. But changing to the following seems to work fine so I do appreciate it!
$scope.getAge = function(birthday){
var birthday = new Date(birthday);
var today = new Date();
var age = ((today - birthday) / (31557600000));
var age = Math.floor( age );
return age;
}
And for the HMTL
{{ getAge(birthdate) }}

To convert currency from US to UK in AngularJS

I tried this code to display but I need AngularJS to automatically convert currency:
<div ng-controller="ctrl">
default currency symbol ($): {{0.00 | currency}}
custom currency symbol (£): {{0.00 | currency:"£"}}
</div>
<script src="index.js"></script>
<script src="uk-locale.js"></script>
As #Andrey said, you should build your own custom filter to handle the currency conversion.
Here's a simple demo of how I would build such a thing:
angular.module('myModule').filter('currency', function() {
var defaultCurrency = '$';
return function(input, currencySymbol) {
var out = "";
currencySymbol = currencySymbol || defaultCurrency;
switch(currencySymbol) {
case '£':
out = 0.609273137 * input; // google
break;
default:
out = input;
}
return out + ' ' + currencySymbol;
}
});
check the online demo
AngularJs currencyFilter just formats output. If you want actually convert currency, you need to make custom filter, for example.
Here is possible example:
angular.module('myFilter', []).filter('currencyConverter', [function() {
function convert(inputValue, currecyId) {
// Your conversion code goes here
}
return function(inputValue, currencyId) {
return convert(inputValue, currencyId);
}
});

How to make a percent formatted input work on latest AngularJS?

I saw this solution http://jsfiddle.net/gronky/GnTDJ/ and it works. That is, when you input 25, it is pushed back to model as 0.25
HTML:
<script type="text/javascript" ng:autobind
src="http://code.angularjs.org/0.9.17/angular-0.9.17.js"></script>
<script>
function Main() {
this.var = '1.0000';
}
</script>
<div ng:controller="Main">
<input type="text" name="var" ng:format="percent">
<pre>var = {{var|json}}</pre>
</div>​
JavaScript:
angular.formatter('percent', {
parse: function(value) {
var m = value.match(/^(\d+)\/(\d+)/);
if (m != null)
return angular.filter.number(parseInt(m[1])/parseInt(m[2]), 2);
return angular.filter.number(parseFloat(value)/100, 2);
},
format: function(value) {
return angular.filter.number(parseFloat(value)*100, 0);
},
});
​
I tried making it work on latest AngularJS, it doesn't work anymore though http://jsfiddle.net/TrJcB/ That is, when you input 25, it is pushed back as 25 also, it doesn't push the correct 0.25 value to model.
Or perhaps there's already a built-in formatter for percent? I wanted currency formatter too, or comma separated number.
Another way to implement percentage filter (works with angular#~1.2):
angular.module('moduleName')
.filter('percentage', ['$filter', function($filter) {
return function(input, decimals) {
return $filter('number')(input*100, decimals)+'%';
};
}]);
How to use it:
<span>{{someNumber | percentage:2}}</span>
The fiddle doesn't work with current Angular version since quite a few APIs have changed since. angular.formatter is no longer available and neither is angular.filter.
The way to write it now is to use a directive and make use of $parser and $formatter available on the directive controller. So your link function will look something like
link: function(scope, ele, attr, ctrl){
ctrl.$parsers.unshift(
function(viewValue){
return $filter('number')(parseFloat(viewValue)/100, 2);
}
);
ctrl.$formatters.unshift(
function(modelValue){
return $filter('number')(parseFloat(modelValue)*100, 2);
}
);
}
Also the filters are now accessed through $filter service. You can find the documentation here: https://docs.angularjs.org/api/ng/filter/number
Updated fiddle for the original example: http://jsfiddle.net/abhaga/DdeCZ/18/
Currency filter is already available in angular: https://docs.angularjs.org/api/ng/filter/currency
Here's a full directive that will parse, format, and perform Angular validation on the inputs. (Tested against angular 1.2 & 1.3.)
We use this so that our data model to/from server can be expressed in decimal notation (0.7634), but we provide a human-readable format to the user (76.34), and enforce a maximum precision. Note that this directive is concerned purely with the numeric aspects. I find it easier to insert a '%' into the template separately, rather than including it here.
It defaults to enforcing input values from -100 to 100, but you can supply your own bounds with attrs pct-min and pct-max.
'use strict';
angular.module('XLDirectives')
.directive('xlPercentage', function($filter) {
// A directive for both formatting and properly validating a percentage value.
// Assumes that our internal model is expressed as floats -1 to +1: .099 is 9.9%
// Formats display into percents 1-100, and parses user inputs down to the model.
// Parses user input as floats between 0 and 100 into floats less than 1.
// Validates user input to be within the range -100 to +100.
// Sets Angular $valid property accordingly on the ngModelController.
// If a `pct-max` or `pct-min` attribute is specified on the <input>, will use those bounds instead.
// If a `pct-decimals` attr present, will truncate inputs accordingly.
function outputFormatter(modelValue, decimals) {
var length = decimals || 2;
if (modelValue != null) {
return $filter('number')(parseFloat(modelValue) * 100, length);
} else {
return undefined;
}
};
function inputParser(viewValue, decimals) {
var length = decimals || 4;
if (viewValue != null) {
return $filter('number')(parseFloat(viewValue) / 100, length);
} else {
return undefined;
}
}
function isWithinBounds(value, upper, lower) {
if (value >= lower && value <= upper) {
return true;
} else {
return false;
}
}
return {
restrict: 'A',
require: 'ngModel',
link: function postLink(scope, element, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue) {
// confirm the input from the view contains numbers, before parsing
var numericStatus = viewValue.match(/(\d+)/),
min = parseFloat(attrs.pctMin) || -100,
max = parseFloat(attrs.pctMax) || 100,
decimals = parseFloat(attrs.pctDecimals) || 4,
bounded = isWithinBounds(viewValue, max, min);
if (numericStatus !== null && bounded) {
ctrl.$setValidity('percentage', true);
// round to max four digits after decimal
return inputParser(viewValue, decimals);
} else {
ctrl.$setValidity('percentage', false);
return undefined
}
});
ctrl.$formatters.unshift(outputFormatter);
// we have to watch for changes, and run the formatter again afterwards
element.on('change', function(e) {
var element = e.target;
element.value = outputFormatter(ctrl.$modelValue, 2);
});
}
};
});
// REFS:
// http://stackoverflow.com/questions/17344828/angularjs-should-i-use-a-filter-to-convert-integer-values-into-percentages
// http://stackoverflow.com/questions/13668440/how-to-make-a-percent-formatted-input-work-on-latest-angularjs
I modified abhaga's answer to allow for .## and ## input. In my opinion this is a lot more user-friendly
link: function(scope, element, attr, ngModel) {
ngModel.$parsers.unshift(
function(viewValue){
var perc = parseFloat(viewValue);
if (perc<0 || perc>100 || !isFinite(perc)){
return null;
}
if (perc>1 && perc<=100){
return parseFloat($filter('number')(perc/100));
}
return perc;
}
);
ngModel.$formatters.unshift(
function(modelValue){
if(!isFinite(modelValue)){
return "";
}
return $filter('number')(parseFloat(modelValue)*100, 2);
}
);
}

Resources