Skip to content

Commit

Permalink
fix(input): Incorrect validation with numeric input and step attribute (
Browse files Browse the repository at this point in the history
#1522)

Closes #1521
  • Loading branch information
rkaraivanov authored Jan 8, 2025
1 parent df490fd commit db36317
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Fixed
- Combo - Rendering issue after Edge browser autofill behavior [#1497](https://github.com/IgniteUI/igniteui-webcomponents/issues/1497)
- Input - Incorrect validation with numeric input and step attribute [#1521](https://github.com/IgniteUI/igniteui-webcomponents/issues/1521)

## [5.1.2] - 2024-11-04
### Added
Expand Down
10 changes: 10 additions & 0 deletions src/components/common/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ export const asPercent = (part: number, whole: number) => (part / whole) * 100;
export const clamp = (number: number, min: number, max: number) =>
Math.max(min, Math.min(number, max));

export function numberOfDecimals(number: number): number {
const decimals = last(number.toString().split('.'));
return decimals ? decimals.length : 0;
}

export function roundPrecise(number: number, magnitude = 1): number {
const factor = 10 ** magnitude;
return Math.round(number * factor) / factor;
}

export function numberInRangeInclusive(
value: number,
min: number,
Expand Down
26 changes: 21 additions & 5 deletions src/components/common/validators.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { DateTimeUtil } from '../date-time-input/date-util.js';
import validatorMessages from './localization/validation-en.js';
import { asNumber, formatString, isDefined } from './util.js';
import {
asNumber,
formatString,
isDefined,
numberOfDecimals,
roundPrecise,
} from './util.js';

type ValidatorHandler<T> = (host: T) => boolean;
type ValidatorMessageFormat<T> = (host: T) => string;
Expand Down Expand Up @@ -93,10 +99,20 @@ export const stepValidator: Validator<{
}> = {
key: 'stepMismatch',
message: 'Value does not conform to step constraint',
isValid: ({ min, step, value }) =>
isDefined(value) && value !== '' && isDefined(step)
? (asNumber(value) - asNumber(min)) % asNumber(step, 1) === 0
: true,
isValid: ({ min, step, value }) => {
if (isDefined(value) && value !== '' && isDefined(step)) {
const _value = asNumber(value) - asNumber(min);
const _step = asNumber(step);
const magnitude = numberOfDecimals(_step) + 1;
const rem = roundPrecise(
Math.abs(_value - _step * Math.round(_value / _step)),
magnitude
);

return !rem;
}
return true;
},
};

export const emailValidator: Validator<{ value: string }> = {
Expand Down
24 changes: 24 additions & 0 deletions src/components/input/input.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,30 @@ describe('Input component', () => {
});
});

describe('issue-1521', () => {
let input: IgcInputComponent;

beforeEach(async () => {
input = await fixture<IgcInputComponent>(html`
<igc-input type="number" step="0.1"></igc-input>
`);
});

it('', () => {
input.value = '1';
expect(input.checkValidity()).to.be.true;

input.value = '1.1';
expect(input.checkValidity()).to.be.true;

input.value = '1.11';
expect(input.checkValidity()).to.be.false;

input.step = 0.01;
expect(input.checkValidity()).to.be.true;
});
});

describe('Form integration', () => {
const spec = createFormAssociatedTestBed<IgcInputComponent>(
html`<igc-input name="input"></igc-input>`
Expand Down
13 changes: 3 additions & 10 deletions src/components/rating/rating.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import {
formatString,
isEmpty,
isLTR,
numberOfDecimals,
roundPrecise,
} from '../common/util.js';
import IgcIconComponent from '../icon/icon.js';
import IgcRatingSymbolComponent from './rating-symbol.js';
Expand Down Expand Up @@ -328,17 +330,8 @@ export default class IgcRatingComponent extends FormAssociatedMixin(
return clamp(value, this.step, this.max);
}

protected getPrecision(num: number) {
const [_, decimal] = num.toString().split('.');
return decimal ? decimal.length : 0;
}

protected round(value: number) {
return Number(
(Math.round(value / this.step) * this.step).toFixed(
this.getPrecision(this.step)
)
);
return roundPrecise(value, numberOfDecimals(this.step));
}

protected clipSymbol(index: number, isLTR = true) {
Expand Down

0 comments on commit db36317

Please sign in to comment.