From 2e2b8a0fc263f9f6805f643cbb810f7f6dfa78bc Mon Sep 17 00:00:00 2001 From: Ed Morales Date: Wed, 15 Aug 2018 13:37:40 -0700 Subject: [PATCH] feat(dynamic-forms): allow elements to be disabled via configuration (#1219) * refactor(dynamic-forms): remove ngModel usage this is needed because we were mixing reactive forms with template driven forms and this usage will be deprecated in angular 7 also used the covalent control value accessor mixin * chore(): remove AbstractControlValueAccessor code since its not needed * fix(): form support was not needed in the dynamic elements since we are injecting the control instance into the underlying element form support was never needed * feat(dynamic-forms): allow elements to be disabled via configuration adding a disabled property to disable properties on the fly without the need of accessing the underlying form * fix(): disable input in dynamic file input * fix(): fix label scss for slider --- .../dynamic-forms.component.html | 23 ++++++++++++- .../dynamic-forms/dynamic-forms.component.ts | 1 + src/platform/dynamic-forms/README.md | 2 ++ .../dynamic-file-input.component.html | 10 ++++-- .../dynamic-slider.component.html | 20 +++++++----- .../dynamic-slider.component.scss | 6 +++- .../dynamic-slider.component.ts | 9 +++++- .../dynamic-forms.component.scss | 5 +++ .../dynamic-forms.component.spec.ts | 32 +++++++++++++++++-- .../dynamic-forms/dynamic-forms.component.ts | 13 ++++++-- .../services/dynamic-forms.service.ts | 3 +- 11 files changed, 104 insertions(+), 20 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 2b75925083..23c8de9c87 100644 --- a/src/app/components/components/dynamic-forms/dynamic-forms.component.html +++ b/src/app/components/components/dynamic-forms/dynamic-forms.component.html @@ -71,8 +71,28 @@

Form elements

- +
+
+ + + + + + + + + + + +
Form elements
Required + Disabled - + folder {{ label }} diff --git a/src/platform/dynamic-forms/dynamic-elements/dynamic-slider/dynamic-slider.component.html b/src/platform/dynamic-forms/dynamic-elements/dynamic-slider/dynamic-slider.component.html index 2a12d441ae..94006dd0f8 100644 --- a/src/platform/dynamic-forms/dynamic-elements/dynamic-slider/dynamic-slider.component.html +++ b/src/platform/dynamic-forms/dynamic-elements/dynamic-slider/dynamic-slider.component.html @@ -1,17 +1,21 @@ -
-
- -
+
+ + +
+ [required]="required" + (blur)="_handleBlur()">
\ No newline at end of file diff --git a/src/platform/dynamic-forms/dynamic-elements/dynamic-slider/dynamic-slider.component.scss b/src/platform/dynamic-forms/dynamic-elements/dynamic-slider/dynamic-slider.component.scss index 955d9c6a45..e7b7b2d720 100644 --- a/src/platform/dynamic-forms/dynamic-elements/dynamic-slider/dynamic-slider.component.scss +++ b/src/platform/dynamic-forms/dynamic-elements/dynamic-slider/dynamic-slider.component.scss @@ -1,6 +1,10 @@ +:host { + .td-dynamic-slider-wrapper { + display: block; + } +} .td-dynamic-slider-field { position: relative; - margin-top: 8px; // [layout="row"] flex-direction: row; // [layout] diff --git a/src/platform/dynamic-forms/dynamic-elements/dynamic-slider/dynamic-slider.component.ts b/src/platform/dynamic-forms/dynamic-elements/dynamic-slider/dynamic-slider.component.ts index ad02821645..e72e55c370 100644 --- a/src/platform/dynamic-forms/dynamic-elements/dynamic-slider/dynamic-slider.component.ts +++ b/src/platform/dynamic-forms/dynamic-elements/dynamic-slider/dynamic-slider.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, ChangeDetectorRef } from '@angular/core'; import { FormControl } from '@angular/forms'; @Component({ @@ -18,4 +18,11 @@ export class TdDynamicSliderComponent { max: number = undefined; + constructor(private _changeDetectorRef: ChangeDetectorRef) {} + + _handleBlur(): void { + setTimeout(() => { + this._changeDetectorRef.markForCheck(); + }); + } } diff --git a/src/platform/dynamic-forms/dynamic-forms.component.scss b/src/platform/dynamic-forms/dynamic-forms.component.scss index aab3fee3f1..c001201342 100644 --- a/src/platform/dynamic-forms/dynamic-forms.component.scss +++ b/src/platform/dynamic-forms/dynamic-forms.component.scss @@ -1,4 +1,9 @@ .td-dynamic-form-wrapper { + ::ng-deep { + .mat-form-field-infix { + width: auto; + } + } // [layout-wrap] flex-wrap: wrap; // [layout] diff --git a/src/platform/dynamic-forms/dynamic-forms.component.spec.ts b/src/platform/dynamic-forms/dynamic-forms.component.spec.ts index b4a5372828..d8f15c261c 100644 --- a/src/platform/dynamic-forms/dynamic-forms.component.spec.ts +++ b/src/platform/dynamic-forms/dynamic-forms.component.spec.ts @@ -100,7 +100,7 @@ describe('Component: TdDynamicForms', () => { fixture.debugElement.query(By.directive(TdDynamicFormsComponent)).componentInstance; expect(dynamicFormsComponent.valid).toBeFalsy(); /* tslint:disable-next-line */ - expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({first_name: null, on_it: true})); + expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({on_it: true})); }); }))); @@ -127,7 +127,7 @@ describe('Component: TdDynamicForms', () => { fixture.debugElement.query(By.directive(TdDynamicFormsComponent)).componentInstance; expect(dynamicFormsComponent.valid).toBeFalsy(); /* tslint:disable-next-line */ - expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({first_name: null, age: 17})); + expect(JSON.stringify(dynamicFormsComponent.value)).toBe(JSON.stringify({age: 17})); }); }))); @@ -319,8 +319,34 @@ describe('Component: TdDynamicForms', () => { }); }))); - it('should render dynamic custom element', async(inject([], () => { + it('should render dynamic elements with one element disabled', 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: 'hexColor', + type: TdDynamicType.Text, + required: true, + default: '#F1F1F1', + }, { + name: 'number', + type: TdDynamicType.Number, + disabled: true, + required: true, + }]; + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(fixture.debugElement.queryAll(By.directive(TdDynamicElementComponent)).length).toBe(2); + 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({hexColor: '#F1F1F1'})); + }); + }))); + + it('should render dynamic custom element', async(inject([], () => { let fixture: ComponentFixture = TestBed.createComponent(TdDynamicFormsTestComponent); let component: TdDynamicFormsTestComponent = fixture.debugElement.componentInstance; diff --git a/src/platform/dynamic-forms/dynamic-forms.component.ts b/src/platform/dynamic-forms/dynamic-forms.component.ts index 25cc89cc9f..6e4637c235 100644 --- a/src/platform/dynamic-forms/dynamic-forms.component.ts +++ b/src/platform/dynamic-forms/dynamic-forms.component.ts @@ -138,10 +138,19 @@ export class TdDynamicFormsComponent implements AfterContentInit { throw new Error(`Dynamic element name: "${elem.name}" is duplicated`); } duplicates.push(elem.name); - if (!this.dynamicForm.get(elem.name)) { + let dynamicElement: AbstractControl = this.dynamicForm.get(elem.name); + if (!dynamicElement) { this.dynamicForm.addControl(elem.name, this._dynamicFormsService.createFormControl(elem)); } else { - this.dynamicForm.get(elem.name).setValidators(this._dynamicFormsService.createValidators(elem)); + dynamicElement.setValue(elem.default); + dynamicElement.markAsPristine(); + dynamicElement.markAsUntouched(); + if (elem.disabled) { + dynamicElement.disable(); + } else { + dynamicElement.enable(); + } + dynamicElement.setValidators(this._dynamicFormsService.createValidators(elem)); } // copy objects so they are only changes when calling this method this._renderedElements.push(Object.assign({}, elem)); diff --git a/src/platform/dynamic-forms/services/dynamic-forms.service.ts b/src/platform/dynamic-forms/services/dynamic-forms.service.ts index e7f104f63a..f576c5646e 100644 --- a/src/platform/dynamic-forms/services/dynamic-forms.service.ts +++ b/src/platform/dynamic-forms/services/dynamic-forms.service.ts @@ -40,6 +40,7 @@ export interface ITdDynamicElementConfig { hint?: string; type: TdDynamicType | TdDynamicElement | Type; required?: boolean; + disabled?: boolean; min?: any; max?: any; minLength?: any; @@ -104,7 +105,7 @@ export class TdDynamicFormsService { */ createFormControl(config: ITdDynamicElementConfig): FormControl { let validator: ValidatorFn = this.createValidators(config); - return new FormControl(config.default, validator); + return new FormControl({ value: config.default, disabled: config.disabled }, validator); } /**