Skip to content

Commit

Permalink
Merge pull request #116 from cloudnc/fix/form-array-error-empty-array
Browse files Browse the repository at this point in the history
improve formGroupErrors when dealing with a FormArray
  • Loading branch information
maxime1992 authored Nov 28, 2019
2 parents 9a7da28 + 13c2535 commit 2499b90
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 6 deletions.
4 changes: 3 additions & 1 deletion projects/ngx-sub-form/src/lib/ngx-sub-form-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ export type ControlsNames<T> = { [K in keyof T]-?: K };
export type ControlMap<T, V> = { [K in keyof T]-?: V };

export type ControlsType<T> = { [K in keyof T]-?: T[K] extends any[] ? FormArray : AbstractControl };
export type FormErrorsType<T> = { [K in keyof T]-?: T[K] extends any[] ? ValidationErrors[] : ValidationErrors };
export type FormErrorsType<T> = {
[K in keyof T]-?: T[K] extends any[] ? (null | ValidationErrors)[] : ValidationErrors
};

export type FormUpdate<FormInterface> = { [FormControlInterface in keyof FormInterface]?: true };

Expand Down
40 changes: 40 additions & 0 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 @@ -786,4 +786,44 @@ describe(`SubArrayComponent`, () => {
expect(subArrayComponent.formGroupControls.vehicles.at(0).disabled).toBe(true);
expect(subArrayComponent.formGroupControls.vehicles.at(1).disabled).toBe(true);
});

it(`should not return an error when a property is a FormArray without any value`, () => {
subArrayComponent.registerOnChange(jasmine.createSpy());

subArrayComponent.writeValue([]);

expect(subArrayComponent.formGroupErrors).toEqual(null);

subArrayComponent.writeValue([
// ok
{ canFire: true, color: 'color-1', crewMemberCount: 1 },
// ok
{ canFire: true, color: 'color-2', crewMemberCount: 10 },
// ok
{ canFire: true, color: 'color-3', crewMemberCount: 112 },
]);

expect(subArrayComponent.formGroupErrors).toEqual(null);
});

it(`should return an error when a property in a FormArray has an error and have null for the other ones in the array`, () => {
subArrayComponent.registerOnChange(jasmine.createSpy());

const values: any[] = [
// nok
null,
// ok
{ canFire: true, color: 'color-1', crewMemberCount: 1 },
// nok
null,
// nok
null,
];

subArrayComponent.writeValue(values);

expect(subArrayComponent.formGroupErrors).toEqual({
vehicles: [{ required: true }, null, { required: true }, { required: true }],
});
});
});
16 changes: 11 additions & 5 deletions projects/ngx-sub-form/src/lib/ngx-sub-form.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ import {
import { FormGroupOptions, NgxFormWithArrayControls, OnFormUpdate, TypedFormGroup } from './ngx-sub-form.types';

type MapControlFunction<FormInterface, MapValue> = (ctrl: AbstractControl, key: keyof FormInterface) => MapValue;
type FilterControlFunction<FormInterface> = (ctrl: AbstractControl, key: keyof FormInterface) => boolean;
type FilterControlFunction<FormInterface> = (
ctrl: AbstractControl,
key: keyof FormInterface,
isCtrlWithinFormArray: boolean,
) => boolean;

export abstract class NgxSubFormComponent<ControlInterface, FormInterface = ControlInterface>
implements ControlValueAccessor, Validator, OnDestroy, OnFormUpdate<FormInterface> {
Expand All @@ -48,7 +52,7 @@ export abstract class NgxSubFormComponent<ControlInterface, FormInterface = Cont
public get formGroupErrors(): FormErrors<FormInterface> {
const errors: FormErrors<FormInterface> = this.mapControls<ValidationErrors | ValidationErrors[] | null>(
ctrl => ctrl.errors,
ctrl => ctrl.invalid,
(ctrl, _, isCtrlWithinFormArray) => (isCtrlWithinFormArray ? true : ctrl.invalid),
true,
) as FormErrors<FormInterface>;

Expand Down Expand Up @@ -139,13 +143,15 @@ export abstract class NgxSubFormComponent<ControlInterface, FormInterface = Cont
const values: MapValue[] = [];

for (let i = 0; i < control.length; i++) {
if (filterControl(control.at(i), key)) {
if (filterControl(control.at(i), key, true)) {
values.push(mapControl(control.at(i), key));
}
}

controls[key] = values;
} else if (control && filterControl(control, key)) {
if (values.length > 0 && values.some(x => !isNullOrUndefined(x))) {
controls[key] = values;
}
} else if (control && filterControl(control, key, false)) {
controls[key] = mapControl(control, key);
}
}
Expand Down

0 comments on commit 2499b90

Please sign in to comment.