jquery-maskmoney
jquery-maskmoney copied to clipboard
Wrong masked values without decimal
Hey guys.. When I'm editing some fields and I have my input rendered as follow:
<input type="text" class="mask-money" value="10000" data-thousands="." data-decimal="," data-prefix="R$ ">
<input type="text" class="mask-money" value="4500" data-thousands="." data-decimal="," data-prefix="R$ ">
<input type="text" class="mask-money" value="1" data-thousands="." data-decimal="," data-prefix="R$ ">
<input type="text" class="mask-money" value="1.1" data-thousands="." data-decimal="," data-prefix="R$ ">
<input type="text" class="mask-money" value="0.8" data-thousands="." data-decimal="," data-prefix="R$ ">
<input type="text" class="mask-money" value="0.88" data-thousands="." data-decimal="," data-prefix="R$ ">
First, feels weird to have to do this in order to mask the fields:
$('.mask-money').maskMoney(); // shouldn't this be enough?
$('.mask-money').maskMoney('mask'); // is this really necessary?
But the problem is that I get this values:
- 100,00 (instead of 10.000,00)
- 45,00 (instead of 4.500,00)
- 0,01 (instead of 1,00)
- 0,11 (instead of 1,10)
- 0,08 (instead of 0,80)
- 0,88 (yeah! fot his one right)
I have this problem too. I'll try to fix this.
@juanmaia @viniciusoyama sorry for taking so long to reply. I will take a look at this in a few days. here's what I'm planning for maskmoney 3.1 https://github.com/plentz/jquery-maskmoney/issues?milestone=6
related #114
Hi @plentz . I've been thinking about it and come up with a solution. I will explain my logic, perhaps you can use something.
First I analysed if this is really an issue because, since the input field uses a mask, the value of it must ALWAYS be masked so this is not an error at all.
To be honest I think that if we want a complete generic solution then what need to be done is just to document that the value on the field must always be masked. Of course I also think that this way will require a lot of extra work from the people that is using the plugin.
The problem:
The maskValue function is waiting for a value already masked or not. But it expects a value with the same precision as configured in the settings so if we use 2 as mask precision the 'pure float value' must be 100.00 and not 100.0
//...
onlyNumbers = value.replace(/[^0-9]/g, "")
//...and...
decimalPart = onlyNumbers.slice(onlyNumbers.length - settings.precision); // wrong assumption
My solution:
We need to check if the field is masked or not and check the precision splitting by the decimal point. But we need to decide if the decimal point to be used is the one from the settings or we will use ".".
In USA the decimal point is the same as most languages float decimal point (.) but here in Brasil the decimal point is ",".
First I modified the maskValue function, but this increased the function complexity and caused a lot of trouble since we must check if the user is inserting a new number or not... Then I decided that the best aproach is to format the value when the plugin is called. So I developed this solution:
// CODE BEFORE...
function clickEvent() {
var input = $input.get(0),
length;
if (input.setSelectionRange) {
length = $input.val().length;
input.setSelectionRange(length, length);
} else {
$input.val($input.val());
}
}
function _convertInitialInputValueToSettingsPrecision(value) {
var isAPureIntegerNumber = value.replace(/[^0-9]/g, "").length == value.length,
isAPureFloatNumber = ((value.replace(/[^0-9]/g, "").length + 1) == value.length) && (value.indexOf(".") != -1),
parsedFloatValue;
// if there is a . in the string we must check if its for
// the thousand indicator or not
// if it is we just check if the last part after the last . has tree numbers
// it it has 3 numbers then we assume that it is not a pure float and the value is
// masked
// this is not bullet proof but can work in most of the situations
// but if the user put a float number with precision of 3 digits then
// we have a problem =[
if (settings.thousands == "." && value.split(".")[value.split(".").length - 1].length == 3) {
isAPureFloatNumber = false;
}
// if the input value is a pure integer or float we must convert
// to the setting precision
if (settings.precision > 0 && (isAPureIntegerNumber || isAPureFloatNumber)) {
parsedFloatValue = parseFloat(value).toFixed(settings.precision);
$input.val(parsedFloatValue);
}
}
if ($input.val()) {
_convertInitialInputValueToSettingsPrecision($input.val());
}
$input.unbind(".maskMoney");
$input.bind("keypress.maskMoney", keypressEvent);
$input.bind("keydown.maskMoney", keydownEvent);
// MORE CODE AFTER...
What do you think?
Tks!
Hey guys,
I also met this issue.
In the input field, I will put the "1" which has no decimal part or "1.0" with only one decimal part as the value, it displayed like "$0.01" or "$0.10", but actually it should be "$1.00".
I looked into the source code, find that maskValue
method to get the integer part and decimal part is not correct.
Original Code
integerPart = onlyNumbers.slice(0, onlyNumbers.length - settings.precision),
...
decimalPart = onlyNumbers.slice(onlyNumbers.length - settings.precision);
I have tried to separate the integer part and decimal part, but it will affect other functions, such as delete. I don't have much time to help you on this, so I try to format the value before use this lib to format it.
Hope you guys can fix it. If later I have time, I will work on this.
Thanks.
I had to write a solution for this too. I wrote a page initializer that compared the length of the input's value to the indexOf(thousandsMarker), and then just appended the thousands marker and the correct number of 0s. I only wrote it to two decimals precision, but it wouldn't be too difficult to port I would think... that particular code is only on my work dev machine, but I can include it here or submit a pull request
As I think, it can be written a method to format the initial value when init the object, then put it into the target field, then call the other methods defined in the object. It can work well. But I only format it at my side, not integrate it into this plugin. If I'm free, I would like to do it.
Any one have idea to solve this issue?
We ran into this issue as well. As a work around I am using javascripts Number() to convert the value to a number during the mask. Below is an example:
http://jsfiddle.net/5pgdq8od/1/
see pull request with possible fix: https://github.com/plentz/jquery-maskmoney/commit/2de7b9a5f09d44731fcd0ef9c0c751eeb24e48b1
jsfiddle with some tests for fix: http://jsfiddle.net/6vyL2v7f/
The above suggested solution isn't working for me. Hope some sort of solution gets put in soon, though! This is a pretty big deal.
@viniciusoyama @juanmaia @sgyyz @mysterryous @ghost @gbass84 hey guys, just a heads up. I'm working in the 3.1 release and this fix will be included. Currently, I don't have a fix, but I already commited the tests for it. If you wanna try to fix it, just open test/index.html and make sure that all tests pass :)
Hi ! Same error here, even setting a float number
$(".js_currency_input").maskMoney('mask', 2.34)
I get £234,00
$(".js_currency_input").maskMoney('mask', 0.34)
I get £34,00
We only support integers ?
I've read everything but I had to solve my problem RIGHT NOW. So here goes an UGLY patch. My values that should show R$ 500,00 were showing as R$ 50,00.
It makes the value of the field get two decimals when it has only one, so 500.0 becomes 500.00, 100.1 becomes 100.10. I do it right before setting the maskMoney on the field, and it fixed it for now (for me)
Be very careful with this patch. I will remove it as soon as the rails gem I'm using for this lib is correct.
function setupMoneyFields(){
var moneyFields = $("input.money");
// Iterating so I can have multiple money fields on the same page.
$.each(moneyFields, function(){
replaceSingleDecimalByDouble($(this));
});
moneyFields.maskMoney({
thousands: '.',
decimal: ',',
prefix: "R$ ",
allowZero: true
});
moneyFields.maskMoney('mask');
}
// Doing this because of Jquery MaskMoney's issue, that is turning 500.0 into R$ 50,00
function replaceSingleDecimalByDouble(jquerySelector){
var currentValue = jquerySelector.val();
jquerySelector.val(currentValue.replace(/\.(\d)\b/, ".$10"));
}
I hope that helps someone somehow, and here goes my +1 for fixing this.
@ghost solution works just fine. Additionally, this must be fixed this as soon as possible. It's unbelievable this issue is open since 2014. It's been almost three years...
+1
I had the same problem. To fix, I change the following code in the jquery.maskMoney.js
function mask() {
var value = $input.val();
if (settings.allowEmpty && value === "") {
return;
}
if (settings.precision > 0 && value.indexOf(settings.decimal) < 0) {
value += settings.decimal + new Array(settings.precision + 1).join(0);
}
$input.val(maskValue(value, settings));
}
to
function mask() {
var value = $input.maskMoney('unmasked')[0].toString();
var decimals = (value.indexOf(".") < 0? 0:(value.length - value.indexOf(".") - 1));
if (settings.allowEmpty && value === "") {
return;
}
if (settings.precision > 0 && settings.precision > decimals) {
value += settings.decimal + new Array(settings.precision - decimals + 1).join(0);
}
$input.val(maskValue(value, settings));
}
UPDATE
I realized that integers still caused problems, so I also made that change to fix. Change:
unmasked: function () {
return this.map(function () {
var value = ($(this).val() || "0"),
isNegative = value.indexOf("-") !== -1,
decimalPart;
// get the last position of the array that is a number(coercion makes "" to be evaluated as false)
$(value.split(/\D/).reverse()).each(function (index, element) {
if (element) {
decimalPart = element;
return false;
}
});
value = value.replace(/\D/g, "");
value = value.replace(new RegExp(decimalPart + "$"), "." + decimalPart);
if (isNegative) {
value = "-" + value;
}
return parseFloat(value);
});
}
to
unmasked: function () {
return this.map(function () {
var value = ($(this).val() || "0"),
isNegative = value.indexOf("-") !== -1,
decimalPart;
// get the last position of the array that is a number(coercion makes "" to be evaluated as false)
var split = value.split(/\D/).reverse();
if (split.length > 1) {
$(split).each(function (index, element) {
if (element) {
decimalPart = element;
return false;
}
});
}
value = value.replace(/\D/g, "");
value = value.replace(new RegExp(decimalPart + "$"), "." + decimalPart);
if (isNegative) {
value = "-" + value;
}
return parseFloat(value);
});
}
In my case I use toFixed(2):
percentualClientesRestante = (percentualClientesRestante).toFixed(2);
+1