From 104e355962b6ebe00f75eabe75354c00cfa0ea7f Mon Sep 17 00:00:00 2001 From: Viktor Kombov Date: Fri, 10 Oct 2025 07:51:01 +0300 Subject: [PATCH] fix(input): update validity when control is marked as touched - 20.1.x --- .../directives/input/input.directive.spec.ts | 22 +++++++++++++++++++ .../lib/directives/input/input.directive.ts | 18 +++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/projects/igniteui-angular/src/lib/directives/input/input.directive.spec.ts b/projects/igniteui-angular/src/lib/directives/input/input.directive.spec.ts index d1c8003d643..dd74f386629 100644 --- a/projects/igniteui-angular/src/lib/directives/input/input.directive.spec.ts +++ b/projects/igniteui-angular/src/lib/directives/input/input.directive.spec.ts @@ -908,6 +908,22 @@ describe('IgxInput', () => { expect(formControl.touched).toBe(true); })); + + it('should update validity when control is marked as touched', fakeAsync(() => { + const fixture = TestBed.createComponent(ReactiveFormComponent); + fixture.detectChanges(); + + const component = fixture.componentInstance; + const igxInput = component.strIgxInput; + + expect(igxInput.valid).toBe(IgxInputState.INITIAL); + + component.markAllAsTouched(); + tick(); + fixture.detectChanges(); + + expect(igxInput.valid).toBe(IgxInputState.INVALID); + })); }); @Component({ @@ -1201,6 +1217,12 @@ class ReactiveFormComponent { this.textareaControl.markAsTouched(); this.textareaControl.updateValueAndValidity(); } + + public markAllAsTouched() { + if (!this.form.valid) { + this.form.markAllAsTouched(); + } + } } @Component({ diff --git a/projects/igniteui-angular/src/lib/directives/input/input.directive.ts b/projects/igniteui-angular/src/lib/directives/input/input.directive.ts index 6701290bd34..84fc82c9547 100644 --- a/projects/igniteui-angular/src/lib/directives/input/input.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/input/input.directive.ts @@ -16,9 +16,10 @@ import { import { AbstractControl, NgControl, - NgModel + NgModel, + TouchedChangeEvent } from '@angular/forms'; -import { Subscription } from 'rxjs'; +import { filter, Subscription } from 'rxjs'; import { IgxInputGroupBase } from '../../input-group/input-group.common'; const nativeValidationAttributes = [ @@ -100,6 +101,7 @@ export class IgxInputDirective implements AfterViewInit, OnDestroy { private _valid = IgxInputState.INITIAL; private _statusChanges$: Subscription; private _valueChanges$: Subscription; + private _touchedChanges$: Subscription; private _fileNames: string; private _disabled = false; @@ -313,6 +315,14 @@ export class IgxInputDirective implements AfterViewInit, OnDestroy { this._valueChanges$ = this.ngControl.valueChanges.subscribe( this.onValueChanged.bind(this) ); + + if (this.ngControl.control) { + this._touchedChanges$ = this.ngControl.control.events + .pipe(filter(e => e instanceof TouchedChangeEvent)) + .subscribe( + this.updateValidityState.bind(this) + ); + } } this.cdr.detectChanges(); @@ -326,6 +336,10 @@ export class IgxInputDirective implements AfterViewInit, OnDestroy { if (this._valueChanges$) { this._valueChanges$.unsubscribe(); } + + if (this._touchedChanges$) { + this._touchedChanges$.unsubscribe(); + } } /** * Sets a focus on the igxInput.