Skip to content

Commit

Permalink
feat(lib): handle FormArray
Browse files Browse the repository at this point in the history
This closes #9
  • Loading branch information
maxime1992 committed Jun 18, 2019
1 parent e1ba611 commit 52a5e76
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 33 deletions.
8 changes: 0 additions & 8 deletions projects/ngx-sub-form/src/lib/ngx-sub-form-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,6 @@ export function subformComponentProviders(

const wrapAsQuote = (str: string): string => `"${str}"`;

export class ArrayNotTransformedBeforeWriteValueError extends Error {
constructor() {
super(
`If you need to pass an array, please wrap it (for now) using "NgxSubFormRemapComponent" into an "array" property for example. Track direct array support here https://github.com/cloudnc/ngx-sub-form/issues/9`,
);
}
}

export class MissingFormControlsError<T extends string> extends Error {
constructor(missingFormControls: T[]) {
super(
Expand Down
36 changes: 18 additions & 18 deletions projects/ngx-sub-form/src/lib/ngx-sub-form.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
NgxSubFormComponent,
NgxSubFormRemapComponent,
MissingFormControlsError,
ArrayNotTransformedBeforeWriteValueError,
NGX_SUB_FORM_HANDLE_VALUE_CHANGES_RATE_STRATEGIES,
} from '../public_api';
import { Observable } from 'rxjs';
Expand Down Expand Up @@ -197,23 +196,24 @@ describe(`NgxSubFormComponent`, () => {

describe(`value is not null nor undefined`, () => {
// we should be able to pass a value `false`, or an empty string for ex
it(`should throw an error when the value is different than an object`, () => {
const invalidValues: any[] = [1, true, false, '', 'some random string'];

// this could happen when using the setValue of patchValue on the top form as those methods are not strongly typed
// but not using `subComponent.formGroup.patchValue` here as the error would not be caught here because not directly
// called by that method
invalidValues.forEach(value =>
expect(() => subComponent.writeValue(value)).toThrow(
new MissingFormControlsError(['color', 'canFire', 'numberOfPeopleOnBoard']),
),
);

const invalidArrays: any[] = [[], [1, 2, 3]];
invalidArrays.forEach(value =>
expect(() => subComponent.writeValue(value)).toThrow(new ArrayNotTransformedBeforeWriteValueError()),
);
});
// todo: array
// it(`should throw an error when the value is different than an object`, () => {
// const invalidValues: any[] = [1, true, false, '', 'some random string'];

// // this could happen when using the setValue of patchValue on the top form as those methods are not strongly typed
// // but not using `subComponent.formGroup.patchValue` here as the error would not be caught here because not directly
// // called by that method
// invalidValues.forEach(value =>
// expect(() => subComponent.writeValue(value)).toThrow(
// new MissingFormControlsError(['color', 'canFire', 'numberOfPeopleOnBoard']),
// ),
// );

// const invalidArrays: any[] = [[], [1, 2, 3]];
// invalidArrays.forEach(value =>
// expect(() => subComponent.writeValue(value)).toThrow(new ArrayNotTransformedBeforeWriteValueError()),
// );
// });

it(`should throw an error when the value is missing any of the required keys to create the form`, () => {
expect(() => subComponent.writeValue({ randomValue: 'ok' } as any)).toThrow(
Expand Down
27 changes: 20 additions & 7 deletions projects/ngx-sub-form/src/lib/ngx-sub-form.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
FormGroup,
ValidationErrors,
Validator,
FormArray,
FormControl,
} from '@angular/forms';
import { merge, Observable, Subscription } from 'rxjs';
import { delay, filter, map, startWith, withLatestFrom } from 'rxjs/operators';
Expand All @@ -15,7 +17,6 @@ import {
ControlsNames,
FormUpdate,
MissingFormControlsError,
ArrayNotTransformedBeforeWriteValueError,
FormErrors,
isNullOrUndefined,
} from './ngx-sub-form-utils';
Expand Down Expand Up @@ -188,24 +189,36 @@ export abstract class NgxSubFormComponent<ControlInterface, FormInterface = Cont

const transformedValue: FormInterface = this.transformToFormGroup(obj);

// for now we throw an error if the transformed value isn't an object with all the expect values
// there's an issue to track support for an array https://github.com/cloudnc/ngx-sub-form/issues/9
if (Array.isArray(transformedValue)) {
throw new ArrayNotTransformedBeforeWriteValueError();
}

const missingKeys: (keyof FormInterface)[] = this.getMissingKeys(transformedValue);
if (missingKeys.length > 0) {
throw new MissingFormControlsError(missingKeys as string[]);
}

this.handleFormArrayControls(transformedValue);

this.formGroup.setValue(transformedValue, {
emitEvent: false,
});
this.formGroup.markAsPristine();
this.formGroup.markAsUntouched();
}

private handleFormArrayControls(obj: any) {
Object.entries(obj).forEach(([key, value]) => {
if (this.formGroup.get(key) instanceof FormArray && Array.isArray(value)) {
const formArray: FormArray = this.formGroup.get(key) as FormArray;

while (formArray.length > value.length) {
formArray.removeAt(formArray.length - 1);
}

while (formArray.length < value.length) {
formArray.push(new FormControl());
}
}
});
}

private getMissingKeys(transformedValue: FormInterface | null) {
// `controlKeys` can be an empty array, empty forms are allowed
const missingKeys: (keyof FormInterface)[] = this.controlKeys.reduce(
Expand Down

0 comments on commit 52a5e76

Please sign in to comment.