From d379e699c4203e38ba2871e3243e7465c80a9ae9 Mon Sep 17 00:00:00 2001 From: QianKai Date: Tue, 16 Apr 2024 15:17:52 +0800 Subject: [PATCH 1/5] feat: Control whether to add `required` class automatically --- projects/ng-dynamic-json-form/src/lib/config-schema.json | 4 ++++ .../src/lib/models/form-layout.interface.ts | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/projects/ng-dynamic-json-form/src/lib/config-schema.json b/projects/ng-dynamic-json-form/src/lib/config-schema.json index 9e19e1f9..b1e80cda 100644 --- a/projects/ng-dynamic-json-form/src/lib/config-schema.json +++ b/projects/ng-dynamic-json-form/src/lib/config-schema.json @@ -383,6 +383,10 @@ "contentCollapsible": { "enum": ["collapse", "expand"], "description": "Enable expand/collapse of content. The default state will be determined by value provided" + }, + "autoAddRequiredClass": { + "type": "boolean", + "description": "Add `required` class automatically to control if there's validator named `required`. Default is true." } } }, diff --git a/projects/ng-dynamic-json-form/src/lib/models/form-layout.interface.ts b/projects/ng-dynamic-json-form/src/lib/models/form-layout.interface.ts index 83b5c046..b2084155 100644 --- a/projects/ng-dynamic-json-form/src/lib/models/form-layout.interface.ts +++ b/projects/ng-dynamic-json-form/src/lib/models/form-layout.interface.ts @@ -21,4 +21,9 @@ export interface FormLayout { /**Enable expand/collapse of content. The default state will be determined by value provided */ contentCollapsible?: 'collapse' | 'expand'; + + /**Add `required` class automatically to control if there's validator named `required`. + * Default is true. + */ + autoAddRequiredClass?: boolean; } From a6e59b581995b7f186b1cef94387e92ea80ee371 Mon Sep 17 00:00:00 2001 From: QianKai Date: Tue, 16 Apr 2024 15:18:14 +0800 Subject: [PATCH 2/5] chore: Use shared template for form title --- .../lib/ng-dynamic-json-form.component.html | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/projects/ng-dynamic-json-form/src/lib/ng-dynamic-json-form.component.html b/projects/ng-dynamic-json-form/src/lib/ng-dynamic-json-form.component.html index aa4a5fe9..324a7146 100644 --- a/projects/ng-dynamic-json-form/src/lib/ng-dynamic-json-form.component.html +++ b/projects/ng-dynamic-json-form/src/lib/ng-dynamic-json-form.component.html @@ -197,19 +197,15 @@ > - - +
@@ -290,7 +286,10 @@ [customComponent]="labelComponents?.[config?.customLabel ?? ''] ?? layoutComponents?.formTitle" [state]="collapsibleState" [ngClass]="{ - required: control | isControlRequired + required: + config?.layout?.autoAddRequiredClass === false + ? null + : (control | isControlRequired) }" > From 63d4f98db36e2698d3460703a27900bb1d18a7c3 Mon Sep 17 00:00:00 2001 From: QianKai Date: Tue, 16 Apr 2024 15:18:25 +0800 Subject: [PATCH 3/5] chore: Code refactor --- .../src/lib/services/form-generator.service.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/projects/ng-dynamic-json-form/src/lib/services/form-generator.service.ts b/projects/ng-dynamic-json-form/src/lib/services/form-generator.service.ts index 8850c12e..981c9b16 100644 --- a/projects/ng-dynamic-json-form/src/lib/services/form-generator.service.ts +++ b/projects/ng-dynamic-json-form/src/lib/services/form-generator.service.ts @@ -4,9 +4,7 @@ import { FormControl, UntypedFormArray, UntypedFormGroup, - ValidatorFn, isFormArray, - isFormControl, isFormGroup, } from '@angular/forms'; import { Subject, takeUntil } from 'rxjs'; @@ -55,8 +53,7 @@ export class FormGeneratorService { control = this._generateFormArray( item.formArray!.template, - arrayLength, - validators + arrayLength ); control.patchValue(item.value ?? []); } @@ -66,6 +63,7 @@ export class FormGeneratorService { } item.formControlName = item.formControlName.replaceAll(/\s/g, '_'); + control.setValidators(validators); formGroup.addControl(item.formControlName, control); } @@ -86,12 +84,9 @@ export class FormGeneratorService { private _generateFormArray( data: FormControlConfig[], - count: number, - validators: ValidatorFn[] + count: number ): UntypedFormArray { - const formArray = new UntypedFormArray([], { - validators, - }); + const formArray = new UntypedFormArray([]); if (!count) { return formArray; From 17656001de9dcfb6d015bbb3138551219a51a2de Mon Sep 17 00:00:00 2001 From: QianKai Date: Tue, 16 Apr 2024 16:45:51 +0800 Subject: [PATCH 4/5] fix: Refactor HTML structure - FormGroup's description should have the same behavior with FormControl --- .../error-message.component.html | 30 ++++++++ .../error-message/error-message.component.ts | 55 +++++++++++-- .../form-control/form-control.component.html | 77 +++---------------- .../form-control/form-control.component.ts | 17 +--- .../lib/ng-dynamic-json-form.component.html | 71 ++++++++++++++--- 5 files changed, 151 insertions(+), 99 deletions(-) create mode 100644 projects/ng-dynamic-json-form/src/lib/components/error-message/error-message.component.html diff --git a/projects/ng-dynamic-json-form/src/lib/components/error-message/error-message.component.html b/projects/ng-dynamic-json-form/src/lib/components/error-message/error-message.component.html new file mode 100644 index 00000000..66cb27e3 --- /dev/null +++ b/projects/ng-dynamic-json-form/src/lib/components/error-message/error-message.component.html @@ -0,0 +1,30 @@ +
+ + + + + + + +
{{ error }}
+
+
+
diff --git a/projects/ng-dynamic-json-form/src/lib/components/error-message/error-message.component.ts b/projects/ng-dynamic-json-form/src/lib/components/error-message/error-message.component.ts index 701459d4..007eb7a9 100644 --- a/projects/ng-dynamic-json-form/src/lib/components/error-message/error-message.component.ts +++ b/projects/ng-dynamic-json-form/src/lib/components/error-message/error-message.component.ts @@ -1,35 +1,50 @@ import { CommonModule } from '@angular/common'; import { + AfterViewInit, Component, DestroyRef, EventEmitter, HostBinding, Input, + OnInit, Output, + ViewChild, + ViewContainerRef, inject, } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { AbstractControl } from '@angular/forms'; import { tap } from 'rxjs'; +import { ControlLayoutDirective } from '../../directives'; import { ValidatorConfig } from '../../models'; +import { FormLayout } from '../../models/form-layout.interface'; +import { + LayoutComponents, + LayoutTemplates, +} from '../../ng-dynamic-json-form.config'; import { FormValidationService } from '../../services/form-validation.service'; @Component({ selector: 'error-message', - template: ` -
{{ error }}
-
`, standalone: true, - imports: [CommonModule], + imports: [CommonModule, ControlLayoutDirective], + templateUrl: './error-message.component.html', }) -export class ErrorMessageComponent { +export class ErrorMessageComponent implements OnInit, AfterViewInit { private _destroyRef = inject(DestroyRef); private _internal_formValidationService = inject(FormValidationService); @Input() control?: AbstractControl | null = null; @Input() validators?: ValidatorConfig[]; + @Input() layout?: FormLayout; + @Input() layoutComponents?: LayoutComponents; + @Input() layoutTemplates?: LayoutTemplates; + @Input() hideErrorMessage?: boolean; @Output() errorMessagesGet = new EventEmitter(); + @ViewChild('componentAnchor', { read: ViewContainerRef }) + private _componentAnchor!: ViewContainerRef; + @HostBinding('class.error-message') hostClass = true; errorMessages: string[] = []; @@ -46,4 +61,34 @@ export class ErrorMessageComponent { ) .subscribe(); } + + ngAfterViewInit(): void { + this._injectComponent(); + } + + get showErrors(): boolean { + const controlTouched = this.control?.touched ?? false; + const controlDirty = this.control?.dirty ?? false; + const hasErrors = !!this.control?.errors; + + if (this.hideErrorMessage) { + return false; + } + + return (controlDirty || controlTouched) && hasErrors; + } + + private _injectComponent(): void { + if (!this.layoutComponents?.errorMessage || !this._componentAnchor) { + return; + } + + this._componentAnchor.clear(); + const componentRef = this._componentAnchor.createComponent( + this.layoutComponents.errorMessage + ); + + componentRef.instance.control = this.control; + componentRef.instance.validators = this.validators; + } } diff --git a/projects/ng-dynamic-json-form/src/lib/components/form-control/form-control.component.html b/projects/ng-dynamic-json-form/src/lib/components/form-control/form-control.component.html index fa3c8492..2a5f29ae 100644 --- a/projects/ng-dynamic-json-form/src/lib/components/form-control/form-control.component.html +++ b/projects/ng-dynamic-json-form/src/lib/components/form-control/form-control.component.html @@ -1,14 +1,4 @@ - - -
- -
- - - - - - - - -
+ - - - - {{ description }} - diff --git a/projects/ng-dynamic-json-form/src/lib/components/form-control/form-control.component.ts b/projects/ng-dynamic-json-form/src/lib/components/form-control/form-control.component.ts index 70e47354..0dc25f86 100644 --- a/projects/ng-dynamic-json-form/src/lib/components/form-control/form-control.component.ts +++ b/projects/ng-dynamic-json-form/src/lib/components/form-control/form-control.component.ts @@ -22,7 +22,7 @@ import { ValidationErrors, Validator, } from '@angular/forms'; -import { EMPTY, Observable, catchError, finalize, of, tap } from 'rxjs'; +import { EMPTY, Observable, finalize, tap } from 'rxjs'; import { UI_BASIC_COMPONENTS } from '../../../ui-basic/ui-basic-components.constant'; import { UiBasicInputComponent } from '../../../ui-basic/ui-basic-input/ui-basic-input.component'; import { ControlLayoutDirective } from '../../directives'; @@ -140,7 +140,6 @@ export class FormControlComponent implements ControlValueAccessor, Validator { ngAfterViewInit(): void { this._injectInputComponent(); - this._injectErrorMessageComponent(); this._viewInitialized = true; this._cd.markForCheck(); this._cd.detectChanges(); @@ -208,20 +207,6 @@ export class FormControlComponent implements ControlValueAccessor, Validator { } } - private _injectErrorMessageComponent(): void { - if (!this.layoutComponents?.errorMessage) return; - - const componentRef = this._injectComponent( - this.errorComponentAnchor, - this.layoutComponents.errorMessage - ); - - if (!componentRef) return; - - componentRef.instance.control = this.control; - componentRef.instance.validators = this.data?.validators; - } - private _fetchOptions(): void { if (!this.data || !this.data.options) return; const { sourceList, trigger, autoSelectFirst, data } = this.data.options; diff --git a/projects/ng-dynamic-json-form/src/lib/ng-dynamic-json-form.component.html b/projects/ng-dynamic-json-form/src/lib/ng-dynamic-json-form.component.html index 324a7146..58609d99 100644 --- a/projects/ng-dynamic-json-form/src/lib/ng-dynamic-json-form.component.html +++ b/projects/ng-dynamic-json-form/src/lib/ng-dynamic-json-form.component.html @@ -72,6 +72,19 @@ >
+ + + + + +
@@ -121,17 +147,20 @@ }" > - - -
+ + + + + +
+ +
From 8af7a0de01721f88919792b9fee58a2c27e06ce5 Mon Sep 17 00:00:00 2001 From: QianKai Date: Tue, 16 Apr 2024 16:47:49 +0800 Subject: [PATCH 5/5] chore: Update version 5.6.0 --- CHANGELOG.md | 14 ++++++++++++++ projects/ng-dynamic-json-form/package.json | 2 +- src/assets/docs/index.md | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d43326eb..23b0f1e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Change log +## 5.6.0 + +### Feature + +- Control whether to add `required` class automatically. + +### Chore + +- Use shared template for form title. + +### Fix + +- FormGroup's description should have the same behavior with FormControl. + ## 5.5.2 ### Chore diff --git a/projects/ng-dynamic-json-form/package.json b/projects/ng-dynamic-json-form/package.json index 46c9e58d..ddac994e 100644 --- a/projects/ng-dynamic-json-form/package.json +++ b/projects/ng-dynamic-json-form/package.json @@ -1,6 +1,6 @@ { "name": "ng-dynamic-json-form", - "version": "5.5.2", + "version": "5.6.0", "author": { "name": "erqk", "url": "https://github.com/erqk" diff --git a/src/assets/docs/index.md b/src/assets/docs/index.md index 15cd8e73..c66e5dff 100644 --- a/src/assets/docs/index.md +++ b/src/assets/docs/index.md @@ -1,4 +1,4 @@ -## 5.5.2 +## 5.6.0 - [English](./v5/index_en.md) - [繁中](./v5/index_zh-TW.md)