ngx-sub-form
Version:

171 lines (164 loc) • 9.86 kB
TypeScript
import { InjectionToken, Type } from '@angular/core';
import { AbstractControl, ValidationErrors, UntypedFormGroup, UntypedFormArray, UntypedFormControl, ControlValueAccessor, Validator } from '@angular/forms';
import { Observable, Subject } from 'rxjs';
import { Nilable } from 'tsdef';
type Controls<T> = {
[K in keyof T]-?: AbstractControl;
};
type ControlsNames<T> = {
[K in keyof T]-?: K;
};
type ControlMap<T, V> = {
[K in keyof T]-?: V;
};
type ControlsType<T> = {
[K in keyof T]-?: T[K] extends any[] ? TypedFormArray<T[K]> : TypedFormControl<T[K]> | (T[K] extends {} ? TypedFormGroup<T[K]> : never);
};
type OneOfControlsTypes<T = any> = ControlsType<T>[keyof ControlsType<T>];
type NewFormErrorsType<T> = {
[K in keyof T]-?: T[K] extends any[] ? Record<number, ValidationErrors> : ValidationErrors;
};
type NewFormErrors<FormInterface> = null | Partial<NewFormErrorsType<FormInterface> & {
formGroup?: ValidationErrors;
}>;
interface TypedAbstractControl<TValue> extends AbstractControl {
value: TValue;
valueChanges: Observable<TValue>;
setValue(value: TValue, options?: Parameters<AbstractControl['setValue']>[1]): void;
patchValue(value: Partial<TValue>, options?: Parameters<AbstractControl['patchValue']>[1]): void;
}
interface TypedFormGroup<TValue extends {}> extends UntypedFormGroup {
value: TValue;
valueChanges: Observable<TValue>;
controls: ControlsType<TValue>;
setValue(value: TValue, options?: Parameters<UntypedFormGroup['setValue']>[1]): void;
patchValue(value: Partial<TValue>, options?: Parameters<UntypedFormGroup['patchValue']>[1]): void;
getRawValue(): TValue;
}
interface TypedFormArray<TValue extends any[]> extends UntypedFormArray {
value: TValue;
valueChanges: Observable<TValue>;
controls: TypedAbstractControl<TValue[0]>[];
setValue(value: TValue, options?: Parameters<UntypedFormArray['setValue']>[1]): void;
patchValue(value: TValue, options?: Parameters<UntypedFormArray['patchValue']>[1]): void;
getRawValue(): TValue;
}
interface TypedFormControl<TValue> extends UntypedFormControl {
value: TValue;
valueChanges: Observable<TValue>;
setValue(value: TValue, options?: Parameters<UntypedFormControl['setValue']>[1]): void;
patchValue(value: Partial<TValue>, options?: Parameters<UntypedFormControl['patchValue']>[1]): void;
}
type KeysWithType<T, V> = {
[K in keyof T]: T[K] extends V ? K : never;
}[keyof T];
type ArrayPropertyKey<T> = KeysWithType<T, Array<any>>;
type ArrayPropertyValue<T, K extends ArrayPropertyKey<T> = ArrayPropertyKey<T>> = T[K] extends Array<infer U> ? U : never;
declare function subformComponentProviders(component: any): {
provide: InjectionToken<ControlValueAccessor>;
useExisting: Type<any>;
multi?: boolean;
}[];
declare class MissingFormControlsError<T extends string> extends Error {
constructor(missingFormControls: T[]);
}
declare const NGX_SUB_FORM_HANDLE_VALUE_CHANGES_RATE_STRATEGIES: {
debounce: <T>(time: number) => (obs: Observable<T>) => Observable<T>;
};
/**
* Easily unsubscribe from an observable stream by appending `takeUntilDestroyed(this)` to the observable pipe.
* If the component already has a `ngOnDestroy` method defined, it will call this first.
*/
declare function takeUntilDestroyed<T>(component: any): (source: Observable<T>) => Observable<T>;
type Nullable<T> = T | null;
type NullableObject<T> = {
[P in keyof T]: Nullable<T[P]>;
};
type TypedValidatorFn<T extends {}> = (formGroup: TypedFormGroup<T>) => ValidationErrors | null;
type TypedAsyncValidatorFn<T extends {}> = (formGroup: TypedFormGroup<T>) => Promise<ValidationErrors | null> | Observable<ValidationErrors | null>;
interface FormGroupOptions<T extends {}> {
/**
* @description The list of validators applied to a control.
*/
validators?: TypedValidatorFn<T> | TypedValidatorFn<T>[] | null;
/**
* @description The list of async validators applied to control.
*/
asyncValidators?: TypedAsyncValidatorFn<T> | TypedAsyncValidatorFn<T>[] | null;
/**
* @description The event name for control to update upon.
*/
updateOn?: 'change' | 'blur' | 'submit';
}
interface NgxFormWithArrayControls<T> {
createFormArrayControl(key: ArrayPropertyKey<T>, value: ArrayPropertyValue<T>): UntypedFormControl;
}
interface ComponentHooks {
onDestroy: Observable<void>;
afterViewInit: Observable<void>;
}
interface FormBindings<ControlInterface> {
readonly writeValue$: Observable<Nilable<ControlInterface>>;
readonly registerOnChange$: Observable<(formValue: ControlInterface | null) => void>;
readonly registerOnTouched$: Observable<() => void>;
readonly setDisabledState$: Observable<boolean>;
}
type ControlValueAccessorComponentInstance = Object & Partial<Record<keyof ControlValueAccessor, never> & Record<keyof Validator, never>>;
interface NgxSubForm<ControlInterface, FormInterface extends {}> {
readonly formGroup: TypedFormGroup<FormInterface>;
readonly formControlNames: ControlsNames<FormInterface>;
readonly formGroupErrors: NewFormErrors<FormInterface>;
readonly createFormArrayControl: CreateFormArrayControlMethod<FormInterface>;
readonly controlValue$: Observable<Nilable<ControlInterface>>;
}
type CreateFormArrayControlMethod<FormInterface> = <K extends ArrayPropertyKey<FormInterface>>(key: K, initialValue: ArrayPropertyValue<FormInterface, K>) => UntypedFormControl;
interface NgxRootForm<ControlInterface, FormInterface extends {}> extends NgxSubForm<ControlInterface, FormInterface> {
}
interface NgxSubFormArrayOptions<FormInterface> {
createFormArrayControl?: CreateFormArrayControlMethod<FormInterface>;
}
interface NgxSubFormRemapOptions<ControlInterface, FormInterface> {
toFormGroup: (obj: ControlInterface) => FormInterface;
fromFormGroup: (formValue: FormInterface) => ControlInterface;
}
type AreTypesSimilar<T, U> = T extends U ? (U extends T ? true : false) : false;
type NgxSubFormRemap<ControlInterface, FormInterface> = AreTypesSimilar<ControlInterface, FormInterface> extends true ? Partial<NgxSubFormRemapOptions<ControlInterface, FormInterface>> : NgxSubFormRemapOptions<ControlInterface, FormInterface>;
type NgxSubFormArray<FormInterface> = ArrayPropertyKey<FormInterface> extends never ? {} : NgxSubFormArrayOptions<FormInterface>;
type NgxSubFormOptions<ControlInterface, FormInterface extends {} = ControlInterface extends {} ? ControlInterface : never> = {
formType: FormType;
formControls: Controls<FormInterface>;
formGroupOptions?: FormGroupOptions<FormInterface>;
emitNullOnDestroy?: boolean;
emitInitialValueOnInit?: boolean;
componentHooks?: ComponentHooks;
touched$?: Observable<void>;
} & NgxSubFormRemap<ControlInterface, FormInterface> & NgxSubFormArray<FormInterface>;
type NgxRootFormOptions<ControlInterface, FormInterface extends {} = ControlInterface extends {} ? ControlInterface : never> = NgxSubFormOptions<ControlInterface, FormInterface> & {
input$: Observable<ControlInterface | undefined>;
output$: Subject<ControlInterface>;
disabled$?: Observable<boolean>;
manualSave$?: Observable<void>;
outputFilterPredicate?: (currentInputValue: FormInterface, outputValue: FormInterface) => boolean;
handleEmissionRate?: (obs$: Observable<FormInterface>) => Observable<FormInterface>;
};
declare enum FormType {
SUB = "Sub",
ROOT = "Root"
}
type NgxFormOptions<ControlInterface, FormInterface extends {}> = NgxSubFormOptions<ControlInterface, FormInterface> | NgxRootFormOptions<ControlInterface, FormInterface>;
declare const getFormGroupErrors: <ControlInterface, FormInterface extends {}>(formGroup: TypedFormGroup<FormInterface>) => NewFormErrors<FormInterface>;
interface FormArrayWrapper<FormInterface> {
key: keyof FormInterface;
control: UntypedFormArray;
}
declare function createFormDataFromOptions<ControlInterface, FormInterface extends {}>(options: NgxSubFormOptions<ControlInterface, FormInterface>): {
formGroup: TypedFormGroup<FormInterface>;
defaultValues: FormInterface;
formControlNames: ControlsNames<FormInterface>;
formArrays: FormArrayWrapper<FormInterface>[];
};
declare const handleFormArrays: <FormInterface>(formArrayWrappers: FormArrayWrapper<FormInterface>[], obj: FormInterface, createFormArrayControl: Required<NgxSubFormArrayOptions<FormInterface>>["createFormArrayControl"]) => void;
declare function createForm<ControlInterface, FormInterface extends {} = ControlInterface extends {} ? ControlInterface : never>(componentInstance: ControlValueAccessorComponentInstance, options: NgxRootFormOptions<ControlInterface, FormInterface>): NgxRootForm<ControlInterface, FormInterface>;
declare function createForm<ControlInterface, FormInterface extends {} = ControlInterface extends {} ? ControlInterface : never>(componentInstance: ControlValueAccessorComponentInstance, options: NgxSubFormOptions<ControlInterface, FormInterface>): NgxSubForm<ControlInterface, FormInterface>;
export { FormType, MissingFormControlsError, NGX_SUB_FORM_HANDLE_VALUE_CHANGES_RATE_STRATEGIES, createForm, createFormDataFromOptions, getFormGroupErrors, handleFormArrays, subformComponentProviders, takeUntilDestroyed };
export type { AreTypesSimilar, ArrayPropertyKey, ArrayPropertyValue, ComponentHooks, ControlMap, ControlValueAccessorComponentInstance, Controls, ControlsNames, ControlsType, CreateFormArrayControlMethod, FormBindings, FormGroupOptions, KeysWithType, NewFormErrors, NewFormErrorsType, NgxFormOptions, NgxFormWithArrayControls, NgxRootForm, NgxRootFormOptions, NgxSubForm, NgxSubFormArrayOptions, NgxSubFormOptions, NgxSubFormRemapOptions, NullableObject, OneOfControlsTypes, TypedAbstractControl, TypedAsyncValidatorFn, TypedFormArray, TypedFormControl, TypedFormGroup, TypedValidatorFn };