Browse Source

custom form field support added

pull/24547/head
erdemcaygor 1 year ago
parent
commit
3f2f25eae9
  1. 45
      npm/ng-packs/packages/components/dynamic-form/src/dynamic-form-field/dynamic-form-field-host.component.ts
  2. 10
      npm/ng-packs/packages/components/dynamic-form/src/dynamic-form-field/dynamic-form-field.component.html
  3. 20
      npm/ng-packs/packages/components/dynamic-form/src/dynamic-form-field/dynamic-form-field.component.ts
  4. 4
      npm/ng-packs/packages/components/dynamic-form/src/dynamic-form.models.ts

45
npm/ng-packs/packages/components/dynamic-form/src/dynamic-form-field/dynamic-form-field-host.component.ts

@ -2,8 +2,6 @@ import {
Component,
ViewChild,
ViewContainerRef,
OnChanges,
SimpleChanges,
ChangeDetectionStrategy,
forwardRef,
Type,
@ -34,26 +32,28 @@ type acceptsFormControl = { formControl?: FormControl };
multi: true
}]
})
export class DynamicFieldHostComponent implements ControlValueAccessor, OnChanges {
component = input<Type<any>>();
export class DynamicFieldHostComponent implements ControlValueAccessor {
component = input<Type<ControlValueAccessor>>();
inputs = input<Record<string, any>>({});
@ViewChild('vcRef', { read: ViewContainerRef, static: true }) viewContainerRef!: ViewContainerRef;
private componentRef?: any;
private lastValue: any;
private value: any;
private disabled = false;
// if child has not implemented ControlValueAccessor. Create form control
private innerControl = new FormControl<any>(null);
readonly destroyRef = inject(DestroyRef);
ngOnChanges(changes: SimpleChanges): void {
if (changes['component']) {
this.createChild();
} else if (this.componentRef && changes['inputs']) {
this.applyInputs();
}
constructor() {
effect(() => {
if (this.component()) {
this.createChild();
} else if (this.componentRef && this.inputs()) {
this.applyInputs();
}
});
}
private createChild() {
@ -72,25 +72,20 @@ export class DynamicFieldHostComponent implements ControlValueAccessor, OnChange
if (this.disabled && instance.setDisabledState) {
instance.setDisabledState(true);
}
// İlk değeri ilet
if (this.lastValue !== undefined) {
instance.writeValue?.(this.lastValue);
// set initial value
if (this.value !== undefined) {
instance.writeValue?.(this.value);
}
} else {
// Child CVA değilse, formControl input’u varsa köprüle
// No CVA -> use form control
if ('formControl' in instance) {
instance.formControl = this.innerControl;
// son değeri uygula
if (this.lastValue !== undefined) {
this.innerControl.setValue(this.lastValue, { emitEvent: false });
// apply initial value/disabled state
if (this.value !== undefined) {
this.innerControl.setValue(this.value, { emitEvent: false });
}
this.innerControl.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(v => this.onChange(v));
this.innerControl.disabled ? null : (this.disabled && this.innerControl.disable({ emitEvent: false }));
} else {
// Son çare: valueChange EventEmitter’ı varsa bağla (konvansiyonel)
if ('valueChange' in instance && instance['valueChange']?.subscribe) {
instance['valueChange'].pipe(takeUntilDestroyed(this.destroyRef)).subscribe((v: any) => this.onChange(v));
}
}
}
}
@ -108,10 +103,8 @@ export class DynamicFieldHostComponent implements ControlValueAccessor, OnChange
return obj && typeof obj.writeValue === 'function' && typeof obj.registerOnChange === 'function';
}
/* --------- CVA (wrapper) --------- */
writeValue(obj: any): void {
this.lastValue = obj;
this.value = obj;
if (!this.componentRef) return;
const inst: any = this.componentRef.instance as controlValueAccessorLike & acceptsFormControl;

10
npm/ng-packs/packages/components/dynamic-form/src/dynamic-form-field/dynamic-form-field.component.html

@ -38,15 +38,7 @@
} @else if (field().type === 'checkbox') {
<!-- Checkbox -->
<div class="form-group form-check">
<input
type="checkbox"
[id]="field().key"
formControlName="value"
[class.is-invalid]="isInvalid"
class="form-check-input">
<label class="form-check-label" [for]="field().key">
{{ field().label | abpLocalization }}
</label>
<abp-checkbox [label]="field().label" formControlName="value" [id]="field().key" />
@if (isInvalid) {
<ng-container [ngTemplateOutlet]="errorTemplate"/>
}

20
npm/ng-packs/packages/components/dynamic-form/src/dynamic-form-field/dynamic-form-field.component.ts

@ -16,7 +16,6 @@ import {
FormControl,
FormControlName,
FormGroupDirective,
FormsModule,
NG_VALUE_ACCESSOR,
NgControl,
FormGroup,
@ -25,6 +24,7 @@ import {
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { NgTemplateOutlet } from '@angular/common';
import { LocalizationPipe } from '@abp/ng.core';
import { FormCheckboxComponent } from '@abp/ng.theme.shared';
export const ABP_DYNAMIC_FORM_FIELD = new InjectionToken<DynamicFormFieldComponent>('AbpDynamicFormField');
@ -40,12 +40,12 @@ const DYNAMIC_FORM_FIELD_CONTROL_VALUE_ACCESSOR = {
styleUrls: ['./dynamic-form-field.component.scss'],
providers: [
{ provide: ABP_DYNAMIC_FORM_FIELD, useExisting: DynamicFormFieldComponent },
DYNAMIC_FORM_FIELD_CONTROL_VALUE_ACCESSOR
DYNAMIC_FORM_FIELD_CONTROL_VALUE_ACCESSOR,
],
host: { class: 'abp-dynamic-form-field' },
exportAs: 'abpDynamicFormField',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [NgTemplateOutlet, LocalizationPipe, ReactiveFormsModule],
imports: [NgTemplateOutlet, LocalizationPipe, ReactiveFormsModule, FormCheckboxComponent],
})
export class DynamicFormFieldComponent implements OnInit, ControlValueAccessor {
field = input.required<FormFieldConfig>();
@ -59,7 +59,7 @@ export class DynamicFormFieldComponent implements OnInit, ControlValueAccessor {
constructor() {
this.fieldFormGroup = this.formBuilder.group({
value: [{ value: '' }]
value: [{ value: '' }],
});
}
@ -97,7 +97,7 @@ export class DynamicFormFieldComponent implements OnInit, ControlValueAccessor {
get isInvalid(): boolean {
if (this.control) {
return (this.control.invalid && (this.control.dirty || this.control.touched));
return this.control.invalid && (this.control.dirty || this.control.touched);
}
return false;
}
@ -106,7 +106,9 @@ export class DynamicFormFieldComponent implements OnInit, ControlValueAccessor {
if (this.control && this.control.errors) {
const errorKeys = Object.keys(this.control.errors);
return errorKeys.map(key => {
const validator = this.field().validators.find(v => v.type.toLowerCase() === key.toLowerCase());
const validator = this.field().validators.find(
v => v.type.toLowerCase() === key.toLowerCase(),
);
console.log(this.field().validators, key);
if (validator && validator.message) {
return validator.message;
@ -114,8 +116,10 @@ export class DynamicFormFieldComponent implements OnInit, ControlValueAccessor {
// Fallback error messages
if (key === 'required') return `${this.field().label} is required`;
if (key === 'email') return 'Please enter a valid email address';
if (key === 'minlength') return `Minimum length is ${this.control.errors[key].requiredLength}`;
if (key === 'maxlength') return `Maximum length is ${this.control.errors[key].requiredLength}`;
if (key === 'minlength')
return `Minimum length is ${this.control.errors[key].requiredLength}`;
if (key === 'maxlength')
return `Maximum length is ${this.control.errors[key].requiredLength}`;
return `${this.field().label} is invalid due to ${key} validation.`;
});
}

4
npm/ng-packs/packages/components/dynamic-form/src/dynamic-form.models.ts

@ -1,3 +1,5 @@
import { Type } from '@angular/core';
import { ControlValueAccessor } from '@angular/forms';
export interface FormFieldConfig {
key: string;
@ -12,7 +14,7 @@ export interface FormFieldConfig {
conditionalLogic?: ConditionalRule[];
order?: number;
gridSize?: number;
component?: any;
component?: Type<ControlValueAccessor>;
}
export interface ValidatorConfig {

Loading…
Cancel
Save