From be37ea1250e8ebb927120ed0244d2c8a10cfcf14 Mon Sep 17 00:00:00 2001 From: Jerry Orta Date: Fri, 8 Sep 2017 13:20:43 -0500 Subject: [PATCH] feat(dynamic-forms): add minLength and maxLength validations (#862) * feat(dynamic-forms): 577 add minLength and maxLength validations closes #577 * fix(): reorder elements on demo so they fit properly * docs(dynamic forms): #577 document api additions closes #577 --- .../dynamic-forms.component.html | 34 +++++++++ .../dynamic-forms/dynamic-forms.component.ts | 32 ++++++--- src/platform/dynamic-forms/README.md | 10 +++ .../dynamic-element.component.ts | 12 ++++ .../dynamic-input.component.html | 2 + .../dynamic-input/dynamic-input.component.ts | 4 ++ .../dynamic-forms.component.html | 2 + .../dynamic-forms.component.spec.ts | 70 +++++++++++++++++++ .../services/dynamic-forms.service.ts | 8 +++ 9 files changed, 166 insertions(+), 8 deletions(-) diff --git a/src/app/components/components/dynamic-forms/dynamic-forms.component.html b/src/app/components/components/dynamic-forms/dynamic-forms.component.html index 3c76e44244..a1450f6ce4 100644 --- a/src/app/components/components/dynamic-forms/dynamic-forms.component.html +++ b/src/app/components/components/dynamic-forms/dynamic-forms.component.html @@ -32,6 +32,8 @@ Required Min value: {{element.min}} Max value: {{element.max}} + MinLength value: {{element.minLength}} + MaxLength value: {{element.maxLength}} @@ -101,6 +103,22 @@

Form elements

name="max"> +
+ + + + + + +
Required @@ -127,6 +145,14 @@

Dynamic Text Elements

Demo + + + + Min length value: {{element.minLength}} + Max length value: {{element.minLength}} + + + @@ -135,6 +161,14 @@

Dynamic Text Elements

+ + + + Min length value: { {element.minLength} } + Max length value: { {element.minLength} } + + + ]]> diff --git a/src/app/components/components/dynamic-forms/dynamic-forms.component.ts b/src/app/components/components/dynamic-forms/dynamic-forms.component.ts index a1df4e4391..ca1a32912c 100644 --- a/src/app/components/components/dynamic-forms/dynamic-forms.component.ts +++ b/src/app/components/components/dynamic-forms/dynamic-forms.component.ts @@ -1,9 +1,14 @@ -import { Component, HostBinding, ViewChild, ViewRef, AfterViewInit } from '@angular/core'; -import { AbstractControl, ValidatorFn, FormGroup, Validators } from '@angular/forms'; +import { Component, HostBinding } from '@angular/core'; +import { AbstractControl, Validators } from '@angular/forms'; import { slideInDownAnimation } from '../../../app.animations'; -import { TdDynamicType, ITdDynamicElementConfig, - TdDynamicElement, ITdDynamicElementValidator, TdDynamicFormsComponent } from '@covalent/dynamic-forms'; +import { + ITdDynamicElementConfig, + ITdDynamicElementValidator, + TdDynamicElement, + TdDynamicFormsComponent, + TdDynamicType, +} from '@covalent/dynamic-forms'; @Component({ selector: 'dynamic-forms-demo', @@ -28,15 +33,22 @@ export class DynamicFormsDemoComponent { required: true, flex: 50, }, { - name: 'textarea', - type: TdDynamicElement.Textarea, - required: false, + name: 'text-length', + label: 'Text Length', + type: TdDynamicElement.Input, + minLength: 4, + maxLength: 12, + flex: 50, }, { name: 'text', type: TdDynamicType.Text, required: false, default: 'Default', - flex: 100, + flex: 50, + }, { + name: 'textarea', + type: TdDynamicElement.Textarea, + required: false, }, { name: 'required-password', label: 'Password Label', @@ -190,6 +202,10 @@ export class DynamicFormsDemoComponent { return type === TdDynamicElement.Slider || type === TdDynamicType.Number; } + isMinMaxLengthSupported(type: TdDynamicElement | TdDynamicType): boolean { + return type === TdDynamicElement.Input || type === TdDynamicType.Text; + } + addElement(): void { if (this.type) { this.dynamicElements.push({ diff --git a/src/platform/dynamic-forms/README.md b/src/platform/dynamic-forms/README.md index 594aa22a19..b90035c60c 100644 --- a/src/platform/dynamic-forms/README.md +++ b/src/platform/dynamic-forms/README.md @@ -45,6 +45,8 @@ export interface ITdDynamicElementConfig { required?: boolean; min?: any; max?: any; + minLength?: string; + maxLength?: string; selections?: any[]; default?: any; validators?: ITdDynamicElementValidator[]; @@ -61,6 +63,8 @@ Example for HTML usage: Required Min value: {{element.min}} Max value: {{element.max}} + Min length value: {{element.minLength}} + Max length value: {{element.minLength}} @@ -76,6 +80,12 @@ export class Demo { name: 'input', type: TdDynamicElement.Input, required: true, + }, { + name: 'textLength', + label: 'Text Length', + type: TdDynamicElement.Input, + minLength: 4, + maxLength: 12, }, { name: 'number', type: TdDynamicType.Number, diff --git a/src/platform/dynamic-forms/dynamic-element.component.ts b/src/platform/dynamic-forms/dynamic-element.component.ts index 5c51d8435e..5569923e44 100644 --- a/src/platform/dynamic-forms/dynamic-element.component.ts +++ b/src/platform/dynamic-forms/dynamic-element.component.ts @@ -85,6 +85,16 @@ export class TdDynamicElementComponent extends AbstractControlValueAccessor */ @Input() max: number = undefined; + /** + * Sets minLength validation checkup (if supported by element). + */ + @Input() minLength: number = undefined; + + /** + * Sets maxLength validation checkup (if supported by element). + */ + @Input() maxLength: number = undefined; + /** * Sets selections for array elements (if supported by element). */ @@ -120,6 +130,8 @@ export class TdDynamicElementComponent extends AbstractControlValueAccessor this._instance.required = this.required; this._instance.min = this.min; this._instance.max = this.max; + this._instance.minLength = this.minLength; + this._instance.maxLength = this.maxLength; this._instance.selections = this.selections; this._instance.registerOnChange((value: any) => { this.value = value; diff --git a/src/platform/dynamic-forms/dynamic-elements/dynamic-input/dynamic-input.component.html b/src/platform/dynamic-forms/dynamic-elements/dynamic-input/dynamic-input.component.html index 2cd003b846..95c9304e26 100644 --- a/src/platform/dynamic-forms/dynamic-elements/dynamic-input/dynamic-input.component.html +++ b/src/platform/dynamic-forms/dynamic-elements/dynamic-input/dynamic-input.component.html @@ -9,6 +9,8 @@ [required]="required" [attr.min]="min" [attr.max]="max" + [attr.minLength]="minLength" + [attr.maxLength]="maxLength" flex/>
diff --git a/src/platform/dynamic-forms/dynamic-elements/dynamic-input/dynamic-input.component.ts b/src/platform/dynamic-forms/dynamic-elements/dynamic-input/dynamic-input.component.ts index cde783d444..bcd7cd0899 100644 --- a/src/platform/dynamic-forms/dynamic-elements/dynamic-input/dynamic-input.component.ts +++ b/src/platform/dynamic-forms/dynamic-elements/dynamic-input/dynamic-input.component.ts @@ -29,4 +29,8 @@ export class TdDynamicInputComponent extends AbstractControlValueAccessor implem max: number = undefined; + minLength: number = undefined; + + maxLength: number = undefined; + } diff --git a/src/platform/dynamic-forms/dynamic-forms.component.html b/src/platform/dynamic-forms/dynamic-forms.component.html index 0847917c5d..d4eb501edf 100644 --- a/src/platform/dynamic-forms/dynamic-forms.component.html +++ b/src/platform/dynamic-forms/dynamic-forms.component.html @@ -15,6 +15,8 @@ [required]="element.required" [min]="element.min" [max]="element.max" + [minLength]="element.minLength" + [maxLength]="element.maxLength" [selections]="element.selections">
{ }); }))); + it('should render dynamic elements and show form invalid because character length is less than minLength', async(inject([], () => { + + let fixture: ComponentFixture = TestBed.createComponent(TdDynamicFormsTestComponent); + let component: TdDynamicFormsTestComponent = fixture.debugElement.componentInstance; + + expect(fixture.debugElement.queryAll(By.directive(TdDynamicElementComponent)).length).toBe(0); + component.elements = [{ + name: 'password', + type: TdDynamicType.Text, + minLength: 8, + default: 'mypwd', + }]; + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(fixture.debugElement.queryAll(By.directive(TdDynamicElementComponent)).length).toBe(1); + let dynamicFormsComponent: TdDynamicFormsComponent = + fixture.debugElement.query(By.directive(TdDynamicFormsComponent)).componentInstance; + expect(dynamicFormsComponent.valid).toBeFalsy(); + /* tslint:disable-next-line */ + expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({password: 'mypwd'})); + }); + }))); + + it('should render dynamic elements and show form invalid because character length is more than maxLength', async(inject([], () => { + + let fixture: ComponentFixture = TestBed.createComponent(TdDynamicFormsTestComponent); + let component: TdDynamicFormsTestComponent = fixture.debugElement.componentInstance; + + expect(fixture.debugElement.queryAll(By.directive(TdDynamicElementComponent)).length).toBe(0); + component.elements = [{ + name: 'password', + type: TdDynamicType.Text, + maxLength: 8, + default: 'myVeryLongString', + }]; + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(fixture.debugElement.queryAll(By.directive(TdDynamicElementComponent)).length).toBe(1); + let dynamicFormsComponent: TdDynamicFormsComponent = + fixture.debugElement.query(By.directive(TdDynamicFormsComponent)).componentInstance; + expect(dynamicFormsComponent.valid).toBeFalsy(); + /* tslint:disable-next-line */ + expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({password: 'myVeryLongString'})); + }); + }))); + + it('should render dynamic elements and show form valid', async(inject([], () => { + + let fixture: ComponentFixture = TestBed.createComponent(TdDynamicFormsTestComponent); + let component: TdDynamicFormsTestComponent = fixture.debugElement.componentInstance; + + expect(fixture.debugElement.queryAll(By.directive(TdDynamicElementComponent)).length).toBe(0); + component.elements = [{ + name: 'password', + type: TdDynamicType.Text, + minLength: 8, + maxLength: 20, + default: 'mySuperSecretPw', + }]; + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(fixture.debugElement.queryAll(By.directive(TdDynamicElementComponent)).length).toBe(1); + let dynamicFormsComponent: TdDynamicFormsComponent = + fixture.debugElement.query(By.directive(TdDynamicFormsComponent)).componentInstance; + expect(dynamicFormsComponent.valid).toBeTruthy(); + /* tslint:disable-next-line */ + expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({password: 'mySuperSecretPw'})); + }); + }))); + it('should render dynamic elements and show form invalid with custom validation', async(inject([], () => { let fixture: ComponentFixture = TestBed.createComponent(TdDynamicFormsTestComponent); diff --git a/src/platform/dynamic-forms/services/dynamic-forms.service.ts b/src/platform/dynamic-forms/services/dynamic-forms.service.ts index 0634867bb1..3c77bca1ea 100644 --- a/src/platform/dynamic-forms/services/dynamic-forms.service.ts +++ b/src/platform/dynamic-forms/services/dynamic-forms.service.ts @@ -38,6 +38,8 @@ export interface ITdDynamicElementConfig { required?: boolean; min?: any; max?: any; + minLength?: any; + maxLength?: any; selections?: string[] | { value: any, label: string }[]; default?: any; flex?: number; @@ -111,6 +113,12 @@ export class TdDynamicFormsService { if (config.min || config.min === 0) { validator = Validators.compose([validator, Validators.min(parseFloat(config.min))]); } + if (config.maxLength || config.maxLength === 0) { + validator = Validators.compose([validator, Validators.maxLength(parseFloat(config.maxLength))]); + } + if (config.minLength || config.minLength === 0) { + validator = Validators.compose([validator, Validators.minLength(parseFloat(config.minLength))]); + } // Add provided custom validators to the validator function if (config.validators) { config.validators.forEach((validatorConfig: ITdDynamicElementValidator) => {