Skip to content

Commit

Permalink
feat(dynamic-form-group): Group type safety
Browse files Browse the repository at this point in the history
Only allow the use of the type of the property or a Dynamic Form Group or a Form Array
  • Loading branch information
ScottMGerstl committed Jan 11, 2019
1 parent fbed32c commit f183e49
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class UserPanelComponent {
name: '',
company: this.fb.group(Company, {
name: '',
regionNum: ''
regionNum: null
})
})
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { FormBuilder } from '@angular/forms';
import { plainToClass } from 'class-transformer';
import { ClassType } from 'class-transformer/ClassTransformer';
import { ValidatorOptions } from 'class-validator';
import 'reflect-metadata';
import { Dictionary } from '../models';
import { DynamicFormGroupConfig } from '../models/dynamic-form-group-config';
import { DynamicFormGroup, getClassValidators } from './dynamic-form-group';
import { plainToClass } from 'class-transformer';
import { DynamicFormGroup, FormModel, getClassValidators } from './dynamic-form-group';

export class DynamicFormBuilder extends FormBuilder {

// ******************
// Public API

group<TModel>(factoryModel: ClassType<TModel>, controlsConfig?: Dictionary | DynamicFormGroupConfig, extra?: DynamicFormGroupConfig): DynamicFormGroup<TModel> {
group<TModel>(factoryModel: ClassType<TModel>, controlsConfig?: FormModel<TModel> | DynamicFormGroupConfig, extra?: DynamicFormGroupConfig): DynamicFormGroup<TModel> {

// Process the group with the controlsConfig passed into extra instead. (What does this accomplish?)
if (controlsConfig && (controlsConfig.legacyOrOpts || controlsConfig.customValidatorOptions)) {
if (controlsConfig && ((controlsConfig as DynamicFormGroupConfig).legacyOrOpts || (controlsConfig as DynamicFormGroupConfig).customValidatorOptions)) {
return this.group(factoryModel, undefined, controlsConfig);
}

Expand All @@ -24,10 +23,10 @@ export class DynamicFormBuilder extends FormBuilder {
extra.customValidatorOptions = { validationError: { target: false } };
}

let newControlsConfig: Dictionary;
let newControlsConfig: FormModel<TModel>;

if (controlsConfig !== undefined) {
newControlsConfig = controlsConfig;
newControlsConfig = controlsConfig as FormModel<TModel>;
}

// experimental
Expand Down
20 changes: 12 additions & 8 deletions libs/ngx-dynamic-form-builder/src/lib/utils/dynamic-form-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,21 @@ import 'reflect-metadata';
import { BehaviorSubject } from 'rxjs';
import { Dictionary, ShortValidationErrors } from '../models';

// Enforces the properties of the object, if supplied, to be of the original type or DynamicFormGroup or, FormArray
export type FormModel<T> = { [P in keyof T]?: T[P] | DynamicFormGroup<any> | FormArray };

export class DynamicFormGroup<TModel> extends FormGroup {

public customValidateErrors = new BehaviorSubject<ShortValidationErrors>({});
public formErrors: ShortValidationErrors;
public formFields: Dictionary;

private _object: TModel;
private _externalErrors: ShortValidationErrors;
private _validatorOptions: ValidatorOptions;
private _fb = new FormBuilder();

constructor(public factoryModel: ClassType<TModel>, public fields: Dictionary, public defaultValidatorOptions?: ValidatorOptions) {
constructor(public factoryModel: ClassType<TModel>, fields: FormModel<TModel>, public defaultValidatorOptions?: ValidatorOptions) {
super({});
/*
const classValidators = DynamicFormGroup.getClassValidators<TModel>(
Expand All @@ -38,7 +42,7 @@ export class DynamicFormGroup<TModel> extends FormGroup {
this.defaultValidatorOptions
);
});*/
this.fields = this.onlyFields(this.fields);
this.formFields = this.onlyFields(fields);
}

// Getters & Setters
Expand Down Expand Up @@ -175,21 +179,21 @@ export class DynamicFormGroup<TModel> extends FormGroup {
}

// Helpers
private onlyFields(fields: Dictionary) {
const newFields = {};
private onlyFields(fields: FormModel<any>): Dictionary {
const newFields: Dictionary = {};

if (fields !== undefined) {
Object.keys(fields).forEach(key => {
if (fields[key] instanceof DynamicFormGroup) {
// Group: recursive
newFields[key] = this.onlyFields((fields[key] as DynamicFormGroup<any>).fields);
newFields[key] = this.onlyFields((fields[key] as DynamicFormGroup<any>).formFields);
}
else {
// Array
if (fields[key] instanceof FormArray) {
if ((fields[key] as FormArray).controls[0] instanceof DynamicFormGroup) {
// Group within Array: recursive
newFields[key] = this.onlyFields(((fields[key] as FormArray).controls[0] as DynamicFormGroup<any>).fields);
newFields[key] = this.onlyFields(((fields[key] as FormArray).controls[0] as DynamicFormGroup<any>).formFields);
}
else {
// Control within Array
Expand Down Expand Up @@ -375,11 +379,11 @@ export class DynamicFormGroup<TModel> extends FormGroup {
for (let i = 0; i < objectArray.length; i++) {
if (isFormGroup) {
// Create FormGroup
const dynamicFormGroup = new DynamicFormGroup(prevFormGroup.factoryModel, prevFormGroup.fields, this._validatorOptions);
const dynamicFormGroup = new DynamicFormGroup(prevFormGroup.factoryModel, prevFormGroup.formFields, this._validatorOptions);

dynamicFormGroup.setParent(this);

const classValidators = getClassValidators<TModel>(prevFormGroup.factoryModel, prevFormGroup.fields, this._validatorOptions);
const classValidators = getClassValidators<TModel>(prevFormGroup.factoryModel, prevFormGroup.formFields, this._validatorOptions);
const formGroup = this._fb.group(classValidators);

// Add all controls to the form group
Expand Down

0 comments on commit f183e49

Please sign in to comment.