From 2ec4f15643264f32d60eb12f9669c7a6a0275d76 Mon Sep 17 00:00:00 2001 From: iRealNirmal Date: Fri, 21 May 2021 21:53:29 +0530 Subject: [PATCH] fix(forms): Add float number support for min and max validator (#42223) Added float number support for minValidator and maxValidator Closes #42215 PR Close #42223 --- packages/forms/src/directives/validators.ts | 4 +- .../forms/test/reactive_integration_spec.ts | 68 +++++++++++++++++++ .../forms/test/template_integration_spec.ts | 67 ++++++++++++++++++ packages/forms/test/validators_spec.ts | 28 ++++++++ 4 files changed, 165 insertions(+), 2 deletions(-) diff --git a/packages/forms/src/directives/validators.ts b/packages/forms/src/directives/validators.ts index eff697b1286e1..566e0167acc07 100644 --- a/packages/forms/src/directives/validators.ts +++ b/packages/forms/src/directives/validators.ts @@ -178,7 +178,7 @@ export class MaxValidator extends AbstractValidatorDirective implements OnChange /** @internal */ inputName = 'max'; /** @internal */ - normalizeInput = (input: string): number => parseInt(input, 10); + normalizeInput = (input: string): number => parseFloat(input); /** @internal */ createValidator = (max: number): ValidatorFn => maxValidator(max); /** @@ -238,7 +238,7 @@ export class MinValidator extends AbstractValidatorDirective implements OnChange /** @internal */ inputName = 'min'; /** @internal */ - normalizeInput = (input: string): number => parseInt(input, 10); + normalizeInput = (input: string): number => parseFloat(input); /** @internal */ createValidator = (min: number): ValidatorFn => minValidator(min); /** diff --git a/packages/forms/test/reactive_integration_spec.ts b/packages/forms/test/reactive_integration_spec.ts index 588c344b42a52..acbe4eb995c64 100644 --- a/packages/forms/test/reactive_integration_spec.ts +++ b/packages/forms/test/reactive_integration_spec.ts @@ -2563,6 +2563,40 @@ const ValueAccessorB = createControlValueAccessor('[cva-b]'); expect(form.controls.pin.errors).toEqual({max: {max: 1, actual: 2}}); }); + it('should validate max for float number', () => { + const fixture = initTest(getComponent(dir)); + const control = new FormControl(10.25); + fixture.componentInstance.control = control; + fixture.componentInstance.form = new FormGroup({'pin': control}); + fixture.componentInstance.max = 10.35; + fixture.detectChanges(); + + const input = fixture.debugElement.query(By.css('input')).nativeElement; + const form = fixture.componentInstance.form; + + expect(input.value).toEqual('10.25'); + expect(form.valid).toBeTruthy(); + expect(form.controls.pin.errors).toBeNull(); + + input.value = 10.15; + dispatchEvent(input, 'input'); + expect(form.value).toEqual({pin: 10.15}); + expect(form.valid).toBeTruthy(); + expect(form.controls.pin.errors).toBeNull(); + + fixture.componentInstance.max = 10.05; + fixture.detectChanges(); + + expect(form.valid).toBeFalse(); + expect(form.controls.pin.errors).toEqual({max: {max: 10.05, actual: 10.15}}); + + input.value = 10.01; + dispatchEvent(input, 'input'); + expect(form.value).toEqual({pin: 10.01}); + expect(form.valid).toBeTruthy(); + expect(form.controls.pin.errors).toBeNull(); + }); + it('should apply max validation when control value is defined as a string', () => { const fixture = initTest(getComponent(dir)); const control = new FormControl('5'); @@ -2615,6 +2649,40 @@ const ValueAccessorB = createControlValueAccessor('[cva-b]'); expect(form.controls.pin.errors).toEqual({min: {min: 5, actual: 2}}); }); + it('should validate min for float number', () => { + const fixture = initTest(getComponent(dir)); + const control = new FormControl(10.25); + fixture.componentInstance.control = control; + fixture.componentInstance.form = new FormGroup({'pin': control}); + fixture.componentInstance.max = 10.50; + fixture.componentInstance.min = 10.25; + fixture.detectChanges(); + + const input = fixture.debugElement.query(By.css('input')).nativeElement; + const form = fixture.componentInstance.form; + + expect(input.value).toEqual('10.25'); + expect(form.valid).toBeTruthy(); + expect(form.controls.pin.errors).toBeNull(); + + input.value = 10.35; + dispatchEvent(input, 'input'); + expect(form.value).toEqual({pin: 10.35}); + expect(form.valid).toBeTruthy(); + expect(form.controls.pin.errors).toBeNull(); + + fixture.componentInstance.min = 10.40; + fixture.detectChanges(); + expect(form.valid).toBeFalse(); + expect(form.controls.pin.errors).toEqual({min: {min: 10.40, actual: 10.35}}); + + input.value = 10.45; + dispatchEvent(input, 'input'); + expect(form.value).toEqual({pin: 10.45}); + expect(form.valid).toBeTruthy(); + expect(form.controls.pin.errors).toBeNull(); + }); + it('should apply min validation when control value is defined as a string', () => { const fixture = initTest(getComponent(dir)); const control = new FormControl('5'); diff --git a/packages/forms/test/template_integration_spec.ts b/packages/forms/test/template_integration_spec.ts index e35d281d64b08..859c25f9e8fef 100644 --- a/packages/forms/test/template_integration_spec.ts +++ b/packages/forms/test/template_integration_spec.ts @@ -1540,6 +1540,40 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat expect(form.controls.max.errors).toBeNull(); })); + it('should validate max for float number', fakeAsync(() => { + const fixture = initTest(NgModelMaxValidator); + fixture.componentInstance.max = 10.25; + fixture.detectChanges(); + tick(); + + const input = fixture.debugElement.query(By.css('input')).nativeElement; + const form = fixture.debugElement.children[0].injector.get(NgForm); + + input.value = ''; + dispatchEvent(input, 'input'); + fixture.detectChanges(); + expect(form.valid).toEqual(true); + expect(form.controls.max.errors).toBeNull(); + + input.value = 10.25; + dispatchEvent(input, 'input'); + fixture.detectChanges(); + expect(form.valid).toEqual(true); + expect(form.controls.max.errors).toBeNull(); + + input.value = 10.15; + dispatchEvent(input, 'input'); + fixture.detectChanges(); + expect(form.valid).toEqual(true); + expect(form.controls.max.errors).toBeNull(); + + input.value = 10.35; + dispatchEvent(input, 'input'); + fixture.detectChanges(); + expect(form.valid).toEqual(false); + expect(form.controls.max.errors).toEqual({max: {max: 10.25, actual: 10.35}}); + })); + it('should apply max validation when control value is defined as a string', fakeAsync(() => { const fixture = initTest(NgModelMaxValidator); fixture.componentInstance.max = 10; @@ -1617,6 +1651,39 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat expect(form.controls.min.errors).toEqual({min: {min: 10, actual: 9}}); })); + it('should validate min for float number', fakeAsync(() => { + const fixture = initTest(NgModelMinValidator); + fixture.componentInstance.min = 10.25; + fixture.detectChanges(); + tick(); + + const input = fixture.debugElement.query(By.css('input')).nativeElement; + const form = fixture.debugElement.children[0].injector.get(NgForm); + + input.value = ''; + dispatchEvent(input, 'input'); + fixture.detectChanges(); + expect(form.valid).toEqual(true); + expect(form.controls.min.errors).toBeNull(); + + input.value = 10.35; + dispatchEvent(input, 'input'); + fixture.detectChanges(); + expect(form.valid).toEqual(true); + expect(form.controls.min.errors).toBeNull(); + + input.value = 10.25; + dispatchEvent(input, 'input'); + fixture.detectChanges(); + expect(form.valid).toEqual(true); + expect(form.controls.min.errors).toBeNull(); + + input.value = 10.15; + dispatchEvent(input, 'input'); + fixture.detectChanges(); + expect(form.valid).toEqual(false); + expect(form.controls.min.errors).toEqual({min: {min: 10.25, actual: 10.15}}); + })); it('should apply min validation when control value is defined as a string', fakeAsync(() => { const fixture = initTest(NgModelMinValidator); fixture.componentInstance.min = 10; diff --git a/packages/forms/test/validators_spec.ts b/packages/forms/test/validators_spec.ts index db5d5262d5ba7..a42c14774ce8a 100644 --- a/packages/forms/test/validators_spec.ts +++ b/packages/forms/test/validators_spec.ts @@ -61,6 +61,20 @@ describe('Validators', () => { expect(Validators.min(2)(new FormControl('1'))).toEqual({'min': {'min': 2, 'actual': '1'}}); }); + it('should not error on small float number validation', () => { + expect(Validators.min(1.20)(new FormControl(1.25))).toBeNull(); + }); + + it('should not error on equal float values', () => { + expect(Validators.min(1.25)(new FormControl(1.25))).toBeNull(); + }); + + it('should return a validation error on big values', () => { + expect(Validators.min(1.25)(new FormControl(1.20))).toEqual({ + 'min': {'min': 1.25, 'actual': 1.20} + }); + }); + it('should not error on big values', () => { expect(Validators.min(2)(new FormControl(3))).toBeNull(); }); @@ -105,6 +119,20 @@ describe('Validators', () => { expect(Validators.max(2)(new FormControl('aaa'))).toBeNull(); }); + it('should not error on small float number validation', () => { + expect(Validators.max(1.20)(new FormControl(1.15))).toBeNull(); + }); + + it('should not error on equal float values', () => { + expect(Validators.max(1.25)(new FormControl(1.25))).toBeNull(); + }); + + it('should return a validation error on big values', () => { + expect(Validators.max(1.25)(new FormControl(1.30))).toEqual({ + 'max': {'max': 1.25, 'actual': 1.30} + }); + }); + it('should return a validation error on big values', () => { expect(Validators.max(2)(new FormControl(3))).toEqual({'max': {'max': 2, 'actual': 3}}); });