diff --git a/src/directives/input/input.directive.spec.ts b/src/directives/input/input.directive.spec.ts index 3ad574bf056..b843535bb32 100644 --- a/src/directives/input/input.directive.spec.ts +++ b/src/directives/input/input.directive.spec.ts @@ -1,6 +1,6 @@ import { Component, ViewChild } from "@angular/core"; import { async, TestBed } from "@angular/core/testing"; -import { FormsModule } from "@angular/forms"; +import { FormBuilder, FormsModule, ReactiveFormsModule, Validators } from "@angular/forms"; import { By } from "@angular/platform-browser"; import { IgxInputGroupComponent, IgxInputGroupModule } from "../../input-group/input-group.component"; import { IgxInputDirective, IgxInputState } from "./input.directive"; @@ -28,11 +28,13 @@ describe("IgxInput", () => { DisabledInputComponent, RequiredInputComponent, RequiredTwoWayDataBoundInputComponent, - DataBoundDisabledInputComponent + DataBoundDisabledInputComponent, + ReactiveFormComponent ], imports: [ IgxInputGroupModule, - FormsModule + FormsModule, + ReactiveFormsModule ] }) .compileComponents(); @@ -162,6 +164,20 @@ describe("IgxInput", () => { const inputElement = fixture.debugElement.query(By.directive(IgxInputDirective)).nativeElement; testRequiredValidation(inputElement, fixture); }); + + it("Should work properly with reactive forms validation.", () => { + const fixture = TestBed.createComponent(ReactiveFormComponent); + fixture.detectChanges(); + + fixture.debugElement.componentInstance.markAsTouched(); + fixture.detectChanges(); + + const invalidInputGroups = fixture.debugElement.nativeElement.querySelectorAll(`.igx-input-group--invalid`); + expect(invalidInputGroups.length).toBe(4); + + const requiredInputGroups = fixture.debugElement.nativeElement.querySelectorAll(`.igx-input-group--required`); + expect(requiredInputGroups.length).toBe(4); + }); }); @Component({ template: ` @@ -239,6 +255,55 @@ class DataBoundDisabledInputComponent { public isDisabled = false; } +@Component({ + template: + `
+
+ + + + +
+ + + + +
+ + + + +
+
+ + + + +
+
` +}) +class ReactiveFormComponent { + form = this.fb.group({ + str: ["", Validators.required], + textarea: ["", Validators.required], + password: ["", Validators.required], + num: [null, Validators.required] + }); + + constructor(private fb: FormBuilder) { } + + public markAsTouched() { + if (!this.form.valid) { + for (const key in this.form.controls) { + if (this.form.controls[key]) { + this.form.controls[key].markAsTouched(); + this.form.controls[key].updateValueAndValidity(); + } + } + } + } +} + function testRequiredValidation(inputElement, fixture) { dispatchInputEvent("focus", inputElement, fixture); inputElement.value = "test"; diff --git a/src/directives/input/input.directive.ts b/src/directives/input/input.directive.ts index 52c3c704dcd..7ed213c6d1a 100644 --- a/src/directives/input/input.directive.ts +++ b/src/directives/input/input.directive.ts @@ -12,7 +12,7 @@ import { Optional, Self } from "@angular/core"; -import { FormControlName, NgControl, NgModel } from "@angular/forms"; +import { AbstractControl, FormControlName, NgControl, NgModel } from "@angular/forms"; import { Subscription } from "rxjs"; import { IgxInputGroupComponent } from "../../input-group/input-group.component"; @@ -77,8 +77,8 @@ export class IgxInputDirective implements AfterViewInit, OnDestroy { public onBlur(event) { this.inputGroup.isFocused = false; this._valid = IgxInputState.INITIAL; - if (this.ngModel) { - if (!this.ngModel.valid) { + if (this.ngControl) { + if (!this.ngControl.valid) { this._valid = IgxInputState.INVALID; } } else if (this._hasValidators() && !this.nativeElement.checkValidity()) { @@ -96,16 +96,15 @@ export class IgxInputDirective implements AfterViewInit, OnDestroy { } ngAfterViewInit() { - if (this.nativeElement.hasAttribute("placeholder")) { - this.inputGroup.hasPlaceholder = true; - } - - if (this.nativeElement.hasAttribute("required")) { - this.inputGroup.isRequired = true; - } - - if (this.nativeElement.hasAttribute("disabled")) { - this.inputGroup.isDisabled = true; + this.inputGroup.hasPlaceholder = this.nativeElement.hasAttribute("placeholder"); + this.inputGroup.isDisabled = this.nativeElement.hasAttribute("disabled"); + this.inputGroup.isRequired = this.nativeElement.hasAttribute("required"); + + // Also check the control's validators for required + if (!this.inputGroup.isRequired && this.ngControl && this.ngControl.control.validator) { + // tslint:disable-next-line:no-object-literal-type-assertion + const validation = this.ngControl.control.validator({} as AbstractControl); + this.inputGroup.isRequired = validation && validation.required; } if ((this.nativeElement.value && this.nativeElement.value.length > 0) || @@ -167,7 +166,7 @@ export class IgxInputDirective implements AfterViewInit, OnDestroy { } } - return false; + return this.ngControl && !!this.ngControl.control.validator || !!this.ngControl.control.asyncValidator; } public get focused() {