Skip to content

Commit

Permalink
fix(FormArray validation): Ensure FormArray level validator errors ar…
Browse files Browse the repository at this point in the history
…e propagated to the parent subform
  • Loading branch information
zakhenry committed Oct 18, 2021
1 parent f520b7f commit 99c7c2f
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 23 deletions.
37 changes: 18 additions & 19 deletions projects/ngx-sub-form/src/lib/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
import {
AbstractControlOptions,
ControlValueAccessor,
FormArray,
FormControl,
FormGroup,
ValidationErrors,
} from '@angular/forms';
import { AbstractControlOptions, ControlValueAccessor, FormArray, FormGroup, ValidationErrors } from '@angular/forms';
import { ReplaySubject } from 'rxjs';
import { Nilable } from 'tsdef';
import {
ControlValueAccessorComponentInstance,
FormBindings,
NgxSubFormArrayOptions,
NgxSubFormOptions,
} from './ngx-sub-form.types';
import {
ArrayPropertyKey,
ControlsNames,
NewFormErrors,
OneOfControlsTypes,
TypedFormGroup,
} from './shared/ngx-sub-form-utils';
import {
ControlValueAccessorComponentInstance,
FormBindings,
NgxSubFormArrayOptions,
NgxSubFormOptions,
} from './ngx-sub-form.types';

export const deepCopy = <T>(value: T): T => JSON.parse(JSON.stringify(value));

Expand Down Expand Up @@ -83,6 +76,12 @@ export const getFormGroupErrors = <ControlInterface, FormInterface>(
const formErrors: NewFormErrors<ControlInterface> = Object.entries<OneOfControlsTypes>(formGroup.controls).reduce<
Exclude<NewFormErrors<ControlInterface>, null>
>((acc, [key, control]) => {
if (control.errors) {
// all of FormControl, FormArray and FormGroup can have errors so we assign them first
const accumulatedGenericError = acc as Record<keyof ControlInterface, ValidationErrors>;
accumulatedGenericError[key as keyof ControlInterface] = control.errors;
}

if (control instanceof FormArray) {
// errors within an array are represented as a map
// with the index and the error
Expand All @@ -98,12 +97,12 @@ export const getFormGroupErrors = <ControlInterface, FormInterface>(
}

if (Object.values(errorsInArray).length > 0) {
const accHoldingArrays = acc as Record<keyof ControlInterface, Record<number, ValidationErrors>>;
accHoldingArrays[key as keyof ControlInterface] = errorsInArray;
const accumulatedArrayErrors = acc as Record<keyof ControlInterface, Record<number, ValidationErrors>>;
if (!(key in accumulatedArrayErrors)) {
accumulatedArrayErrors[key as keyof ControlInterface] = {};
}
Object.assign(accumulatedArrayErrors[key as keyof ControlInterface], errorsInArray);
}
} else if (control.errors) {
const accHoldingNonArrays = acc as Record<keyof ControlInterface, ValidationErrors>;
accHoldingNonArrays[key as keyof ControlInterface] = control.errors;
}

return acc;
Expand Down
1 change: 1 addition & 0 deletions src/app/app.spec.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ context(`EJawa demo`, () => {
},
crewMembers: {
crewMembers: {
minimumCrewMemberCount: 2,
0: {
firstName: {
required: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<fieldset [formGroup]="form.formGroup" class="container">
<legend>Crew members form</legend>
<legend>
Crew members form
<small>(Minimum 2)</small>
</legend>

<div
class="crew-member"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ export class CrewMembersComponent {
public form = createForm<CrewMember[], CrewMembersForm>(this, {
formType: FormType.SUB,
formControls: {
crewMembers: new FormArray([]),
crewMembers: new FormArray([], {
validators: formControl => (formControl.value.length >= 2 ? null : { minimumCrewMemberCount: 2 }),
}),
},
toFormGroup: (obj: CrewMember[]): CrewMembersForm => {
return {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<fieldset [formGroup]="formGroup" class="container">
<legend>Crew members form</legend>
<legend>
Crew members form
<small>(Minimum 2)</small>
</legend>

<div
class="crew-member"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ export class CrewMembersComponent extends NgxSubFormRemapComponent<CrewMember[],
implements NgxFormWithArrayControls<CrewMembersForm> {
protected getFormControls(): Controls<CrewMembersForm> {
return {
crewMembers: new FormArray([]),
crewMembers: new FormArray([], {
validators: formControl => (formControl.value.length >= 2 ? null : { minimumCrewMemberCount: 2 }),
}),
};
}

Expand Down

0 comments on commit 99c7c2f

Please sign in to comment.