Skip to content

Commit c5b7d36

Browse files
committed
fix(input): fix step validation for input[type=number/range]
Previously, the validation would incorrectly fail in certain cases, due to Floating Point Arithmetic limitations. The previous fix for FPA limitations (081d06f) tried to solve the issue by converting the numbers to integers, before doing the actual calculation, but it failed to acount for cases where the conversion returned non-integer (again due to FPA limitations). This commit fixes it by ensuring that the values used in the final calculation are always integers. Fixes angular#15504
1 parent e9a4de0 commit c5b7d36

File tree

2 files changed

+28
-2
lines changed

2 files changed

+28
-2
lines changed

src/ng/directive/input.js

+14-2
Original file line numberDiff line numberDiff line change
@@ -1565,15 +1565,27 @@ function isValidForStep(viewValue, stepBase, step) {
15651565
// and `viewValue` is expected to be a valid stringified number.
15661566
var value = Number(viewValue);
15671567

1568+
var isNonIntegerValue = !isNumberInteger(value);
1569+
var isNonIntegerStepBase = !isNumberInteger(stepBase);
1570+
var isNonIntegerStep = !isNumberInteger(step);
1571+
15681572
// Due to limitations in Floating Point Arithmetic (e.g. `0.3 - 0.2 !== 0.1` or
15691573
// `0.5 % 0.1 !== 0`), we need to convert all numbers to integers.
1570-
if (!isNumberInteger(value) || !isNumberInteger(stepBase) || !isNumberInteger(step)) {
1571-
var decimalCount = Math.max(countDecimals(value), countDecimals(stepBase), countDecimals(step));
1574+
if (isNonIntegerValue || isNonIntegerStepBase || isNonIntegerStep) {
1575+
var valueDecimals = isNonIntegerValue ? countDecimals(value) : 0;
1576+
var stepBaseDecimals = isNonIntegerStepBase ? countDecimals(stepBase) : 0;
1577+
var stepDecimals = isNonIntegerStep ? countDecimals(step) : 0;
1578+
1579+
var decimalCount = Math.max(valueDecimals, stepBaseDecimals, stepDecimals);
15721580
var multiplier = Math.pow(10, decimalCount);
15731581

15741582
value = value * multiplier;
15751583
stepBase = stepBase * multiplier;
15761584
step = step * multiplier;
1585+
1586+
if (isNonIntegerValue) value = Math.round(value);
1587+
if (isNonIntegerStepBase) stepBase = Math.round(stepBase);
1588+
if (isNonIntegerStep) step = Math.round(step);
15771589
}
15781590

15791591
return (value - stepBase) % step === 0;

test/ng/directive/inputSpec.js

+14
Original file line numberDiff line numberDiff line change
@@ -2787,6 +2787,13 @@ describe('input', function() {
27872787
helper.changeInputValueTo('3.5');
27882788
expect(inputElm).toBeValid();
27892789
expect($rootScope.value).toBe(3.5);
2790+
2791+
// 1.16 % 0.01 === 0.009999999999999896
2792+
// 1.16 * 100 === 115.99999999999999
2793+
$rootScope.step = 0.01;
2794+
helper.changeInputValueTo('1.16');
2795+
expect(inputElm).toBeValid();
2796+
expect($rootScope.value).toBe(1.16);
27902797
}
27912798
);
27922799
});
@@ -3681,6 +3688,13 @@ describe('input', function() {
36813688
helper.changeInputValueTo('3.5');
36823689
expect(inputElm).toBeValid();
36833690
expect($rootScope.value).toBe(3.5);
3691+
3692+
// 1.16 % 0.01 === 0.009999999999999896
3693+
// 1.16 * 100 === 115.99999999999999
3694+
$rootScope.step = 0.01;
3695+
helper.changeInputValueTo('1.16');
3696+
expect(inputElm).toBeValid();
3697+
expect($rootScope.value).toBe(1.16);
36843698
}
36853699
);
36863700
}

0 commit comments

Comments
 (0)