Skip to content

Commit

Permalink
feat(Form Arrays): Add typesafety to form array option type
Browse files Browse the repository at this point in the history
  • Loading branch information
zak-cloudnc committed Oct 24, 2020
1 parent 3f2d02c commit 1a9e62d
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 27 deletions.
8 changes: 2 additions & 6 deletions projects/ngx-sub-form/src/lib/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export function createFormDataFromOptions<ControlInterface, FormInterface>(
export const handleFArray = <FormInterface>(
formArrayWrappers: FormArrayWrapper<FormInterface>[],
obj: FormInterface,
createFormArrayControl: NgxSubFormArrayOptions<FormInterface>['createFormArrayControl'] | null,
createFormArrayControl: Required<NgxSubFormArrayOptions<FormInterface>>['createFormArrayControl'],
) => {
if (!formArrayWrappers.length) {
return;
Expand All @@ -177,11 +177,7 @@ export const handleFArray = <FormInterface>(
}

for (let i = control.length; i < value.length; i++) {
if (createFormArrayControl) {
control.insert(i, createFormArrayControl(key as ArrayPropertyKey<FormInterface>, value[i]));
} else {
control.insert(i, new FormControl(value[i]));
}
control.insert(i, createFormArrayControl(key as ArrayPropertyKey<FormInterface>, value[i]));
}
});
};
31 changes: 19 additions & 12 deletions projects/ngx-sub-form/src/lib/ngx-sub-form.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FormControl } from '@angular/forms';
import isEqual from 'fast-deep-equal';
import { getObservableLifecycle } from 'ngx-observable-lifecycle';
import { EMPTY, forkJoin, Observable, of, timer } from 'rxjs';
Expand All @@ -14,7 +15,13 @@ import {
tap,
withLatestFrom,
} from 'rxjs/operators';
import { isNullOrUndefined } from './shared/ngx-sub-form-utils';
import {
ArrayPropertyValue,
isNullOrUndefined,
OneOfControlsTypes,
TypedAbstractControl,
TypedFormControl,
} from './shared/ngx-sub-form-utils';
import {
createFormDataFromOptions,
getControlValueAccessorBindings,
Expand All @@ -25,6 +32,7 @@ import {
import {
ComponentHooks,
ControlValueAccessorComponentInstance,
CreateFormArrayControlMethod,
FormBindings,
FormType,
NgxFormOptions,
Expand All @@ -36,8 +44,9 @@ import {
} from './ngx-sub-form.types';

const optionsHaveInstructionsToCreateArrays = <ControlInterface, FormInterface>(
options: NgxSubFormOptions<ControlInterface, FormInterface>,
): options is NgxSubFormOptions<ControlInterface, FormInterface> & NgxSubFormArrayOptions<FormInterface> => true;
options: NgxFormOptions<ControlInterface, FormInterface> & Partial<NgxSubFormArrayOptions<FormInterface>>,
): options is NgxSubFormOptions<ControlInterface, FormInterface> & NgxSubFormArrayOptions<FormInterface> =>
!!options.createFormArrayControl;

// @todo find a better name
const isRoot = <ControlInterface, FormInterface>(
Expand Down Expand Up @@ -181,19 +190,18 @@ export function createForm<ControlInterface, FormInterface>(
? lifecyleHooks.onDestroy.pipe(mapTo(null))
: EMPTY;

const createFormArrayControl: Required<NgxSubFormArrayOptions<FormInterface>>['createFormArrayControl'] =
optionsHaveInstructionsToCreateArrays<ControlInterface, FormInterface>(options) && options.createFormArrayControl
? options.createFormArrayControl
: (key, initialValue) => new FormControl(initialValue);

const sideEffects = {
broadcastValueToParent$: registerOnChange$.pipe(
switchMap(onChange => broadcastValueToParent$.pipe(tap(value => onChange(value)))),
),
applyUpstreamUpdateOnLocalForm$: transformedValue$.pipe(
tap(value => {
handleFormArrays<FormInterface>(
formArrays,
value,
optionsHaveInstructionsToCreateArrays<ControlInterface, FormInterface>(options)
? options.createFormArrayControl
: null,
);
handleFormArrays<FormInterface>(formArrays, value, createFormArrayControl);

formGroup.reset(value, { emitEvent: false });

Expand Down Expand Up @@ -241,7 +249,6 @@ export function createForm<ControlInterface, FormInterface>(
get formGroupErrors() {
return getFormGroupErrors<ControlInterface, FormInterface>(formGroup);
},
// todo
createFormArrayControl: (options as any).createFormArrayControl,
createFormArrayControl,
};
}
13 changes: 8 additions & 5 deletions projects/ngx-sub-form/src/lib/ngx-sub-form.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Controls,
ControlsNames,
NewFormErrors,
OneOfControlsTypes,
TypedFormGroup,
} from './shared/ngx-sub-form-utils';
import { FormGroupOptions } from './shared/ngx-sub-form.types';
Expand All @@ -33,18 +34,20 @@ export interface NgxSubForm<FormInterface> {
readonly formGroup: TypedFormGroup<FormInterface>;
readonly formControlNames: ControlsNames<FormInterface>;
readonly formGroupErrors: NewFormErrors<FormInterface>;
readonly createFormArrayControl: any;
readonly createFormArrayControl: CreateFormArrayControlMethod<FormInterface>;
}

export type CreateFormArrayControlMethod<FormInterface> = <K extends ArrayPropertyKey<FormInterface>>(
key: K,
initialValue: ArrayPropertyValue<FormInterface, K>,
) => FormControl;

export interface NgxRootForm<ControlInterface> extends NgxSubForm<ControlInterface> {
// @todo: anything else needed here?
}

export interface NgxSubFormArrayOptions<FormInterface> {
createFormArrayControl?: (
key: ArrayPropertyKey<FormInterface>,
value: ArrayPropertyValue<FormInterface>,
) => FormControl;
createFormArrayControl?: CreateFormArrayControlMethod<FormInterface>;
}

export interface NgxSubFormRemapOptions<ControlInterface, FormInterface> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@ export class CrewMembersComponent {
fromFormGroup: (formValue: CrewMembersForm): CrewMember[] => {
return formValue.crewMembers;
},
createFormArrayControl: (
key: ArrayPropertyKey<CrewMembersForm> | undefined,
value: ArrayPropertyValue<CrewMembersForm>,
) => {
createFormArrayControl: (key, value) => {
switch (key) {
case 'crewMembers':
return new FormControl(value, [Validators.required]);
Expand Down

0 comments on commit 1a9e62d

Please sign in to comment.