Skip to content
This repository has been archived by the owner on Jul 21, 2023. It is now read-only.

Commit

Permalink
fix(forms): recursive clearing model from Control<T>
Browse files Browse the repository at this point in the history
Added set of types to recursive clearing model from Control<T>

Closes #76
  • Loading branch information
KostyaTretyak committed Jul 4, 2020
1 parent b43d89b commit e10912a
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 24 deletions.
17 changes: 8 additions & 9 deletions projects/forms/src/lib/form-array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ import {
ValidationErrors,
AbstractControlOptions,
StringKeys,
ExtractModelValue,
FormControlState,
} from './types';

export class FormArray<Item = any, V extends object = ValidatorsModel> extends NativeFormArray {
readonly value: Item[];
readonly valueChanges: Observable<Item[]>;
readonly value: ExtractModelValue<Item>[];
readonly valueChanges: Observable<ExtractModelValue<Item>[]>;
readonly status: Status;
readonly statusChanges: Observable<Status>;
readonly errors: ValidationErrors<V> | null;
Expand Down Expand Up @@ -113,7 +115,7 @@ console.log(arr.value); // ['Nancy', 'Drew']
* The configuration options are passed to the
* [updateValueAndValidity](https://angular.io/api/forms/AbstractControl#updateValueAndValidity) method.
*/
setValue(value: Item[], options: { onlySelf?: boolean; emitEvent?: boolean } = {}) {
setValue(value: ExtractModelValue<Item>[], options: { onlySelf?: boolean; emitEvent?: boolean } = {}) {
return super.setValue(value, options);
}

Expand Down Expand Up @@ -150,7 +152,7 @@ console.log(arr.value); // ['Nancy', null]
* The configuration options are passed to the
* [updateValueAndValidity](https://angular.io/api/forms/AbstractControl#updateValueAndValidity) method.
*/
patchValue(value: Item[], options: { onlySelf?: boolean; emitEvent?: boolean } = {}) {
patchValue(value: ExtractModelValue<Item>[], options: { onlySelf?: boolean; emitEvent?: boolean } = {}) {
return super.patchValue(value, options);
}

Expand Down Expand Up @@ -199,10 +201,7 @@ console.log(this.arr.get(0).status); // 'DISABLED'
* The configuration options are passed to the
* [updateValueAndValidity](https://angular.io/api/forms/AbstractControl#updateValueAndValidity) method.
*/
reset(
value: (Item | { value: Item; disabled: boolean })[] = [],
options: { onlySelf?: boolean; emitEvent?: boolean } = {}
) {
reset(value: FormControlState<Item>[] = [], options: { onlySelf?: boolean; emitEvent?: boolean } = {}) {
return super.reset(value, options);
}

Expand All @@ -213,7 +212,7 @@ console.log(this.arr.get(0).status); // 'DISABLED'
* For enabled controls only, the `value` property is the best way to get the value of the array.
*/
getRawValue() {
return super.getRawValue() as Item[];
return super.getRawValue() as ExtractModelValue<Item>[];
}

/**
Expand Down
5 changes: 4 additions & 1 deletion projects/forms/src/lib/form-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {
ValidatorFn,
AsyncValidatorFn,
ValidatorsModel,
FormControlState,
ExtractModelValue,
ExtractControlValue,
} from './types';
import { FormGroup } from './form-group';
import { FormControl } from './form-control';
Expand Down Expand Up @@ -78,7 +81,7 @@ export class DisabledFormControlComponent {
```
*/
control<T = any, V extends object = ValidatorsModel>(
formState: T | { value: T; disabled: boolean } = null,
formState: FormControlState<T> = null,
validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null,
asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null
): FormControl<T, V> {
Expand Down
14 changes: 8 additions & 6 deletions projects/forms/src/lib/form-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import {
AsyncValidatorFn,
AbstractControlOptions,
ValidatorsModel,
ExtractControlValue,
FormControlState,
} from './types';

export class FormControl<T = any, V extends object = ValidatorsModel> extends NativeFormControl {
readonly value: T;
readonly valueChanges: Observable<T>;
readonly value: ExtractControlValue<T>;
readonly valueChanges: Observable<ExtractControlValue<T>>;
readonly status: Status;
readonly statusChanges: Observable<Status>;
readonly errors: ValidationErrors<V> | null;
Expand All @@ -33,7 +35,7 @@ export class FormControl<T = any, V extends object = ValidatorsModel> extends Na
*
*/
constructor(
formState: T | { value: T; disabled: boolean } = null,
formState: FormControlState<T> = null,
validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null,
asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null
) {
Expand Down Expand Up @@ -64,7 +66,7 @@ export class FormControl<T = any, V extends object = ValidatorsModel> extends Na
*
*/
setValue(
value: T,
value: ExtractControlValue<T>,
options: {
onlySelf?: boolean;
emitEvent?: boolean;
Expand All @@ -85,7 +87,7 @@ export class FormControl<T = any, V extends object = ValidatorsModel> extends Na
* See also: `setValue` for options
*/
patchValue(
value: T,
value: ExtractControlValue<T>,
options: {
onlySelf?: boolean;
emitEvent?: boolean;
Expand Down Expand Up @@ -115,7 +117,7 @@ export class FormControl<T = any, V extends object = ValidatorsModel> extends Na
*
*/
reset(
formState: T | { value: T; disabled: boolean } = null,
formState: FormControlState<T> = null,
options: {
onlySelf?: boolean;
emitEvent?: boolean;
Expand Down
14 changes: 8 additions & 6 deletions projects/forms/src/lib/form-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ import {
ValidationErrors,
AbstractControlOptions,
ControlType,
ExtractGroupValue,
ExtractGroupStateValue,
} from './types';

export class FormGroup<T extends object = any, V extends object = ValidatorsModel> extends NativeFormGroup {
readonly value: T;
readonly valueChanges: Observable<T>;
readonly value: ExtractGroupValue<T>;
readonly valueChanges: Observable<ExtractGroupValue<T>>;
readonly status: Status;
readonly statusChanges: Observable<Status>;
readonly errors: ValidationErrors<V> | null;
Expand Down Expand Up @@ -137,7 +139,7 @@ console.log(form.value); // {first: 'Nancy', last: 'Drew'}
* observables emit events with the latest status and value when the control value is updated.
* When false, no events are emitted.
*/
setValue(value: T, options: { onlySelf?: boolean; emitEvent?: boolean } = {}) {
setValue(value: ExtractGroupStateValue<T>, options: { onlySelf?: boolean; emitEvent?: boolean } = {}) {
return super.setValue(value, options);
}

Expand Down Expand Up @@ -173,7 +175,7 @@ console.log(form.value); // {first: 'Nancy', last: null}
* The configuration options are passed to the
* [updateValueAndValidity](https://angular.io/api/forms/AbstractControl#updateValueAndValidity) method.
*/
patchValue(value: Partial<T>, options: { onlySelf?: boolean; emitEvent?: boolean } = {}) {
patchValue(value: Partial<ExtractGroupStateValue<T>>, options: { onlySelf?: boolean; emitEvent?: boolean } = {}) {
return super.patchValue(value, options);
}

Expand Down Expand Up @@ -233,7 +235,7 @@ console.log(this.form.value); // {first: 'name', last: 'last name'}
console.log(this.form.get('first').status); // 'DISABLED'
```
*/
reset(value: T = {} as any, options: { onlySelf?: boolean; emitEvent?: boolean } = {}) {
reset(value: ExtractGroupStateValue<T> = {} as any, options: { onlySelf?: boolean; emitEvent?: boolean } = {}) {
return super.reset(value, options);
}

Expand All @@ -245,7 +247,7 @@ console.log(this.form.get('first').status); // 'DISABLED'
* it excludes disabled controls in the `FormGroup`.
*/
getRawValue() {
return super.getRawValue() as T;
return super.getRawValue() as ExtractGroupValue<T>;
}

/**
Expand Down
39 changes: 37 additions & 2 deletions projects/forms/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,40 @@ export type ControlType<T, V extends object = ValidatorsModel> = [T] extends [Ex
? FormGroup<T, V>
: FormControl<T, V>;

export type FormControlState<T> =
| null
| ExtractModelValue<T>
| {
value: null | ExtractModelValue<T>;
disabled: boolean;
};

/**
* Clears the form model from `Control<T>` type.
*/
export type ExtractModelValue<T> = [T] extends [ExtractAny<T>]
? any
: [T] extends [Array<infer Item>]
? Array<ExtractModelValue<Item>>
: [T] extends [Control<infer ControlModel>]
? ControlModel
: [T] extends [object]
? ExtractGroupValue<T>
: T;

export type ExtractControlValue<T> = [T] extends [Control<infer ControlModel>] ? ControlModel : T;

/**
* Clears the form model (as object) from `Control<T>` type.
*/
export type ExtractGroupValue<T extends object> = {
[P in keyof T]: ExtractModelValue<T[P]>;
};

export type ExtractGroupStateValue<T extends object> = {
[P in keyof T]: FormControlState<T[P]>;
};

/**
* Form builder control config.
*/
Expand All @@ -112,9 +146,10 @@ export type FbControlConfig<T, V extends object = ValidatorsModel> = [T] extends
* Form builder control.
*/
export type FbControl<T, V extends object = ValidatorsModel> =
| (T | { value: T; disabled: boolean })
| ExtractModelValue<T>
| FormControlState<T>
| [
T | { value: T; disabled: boolean },
FormControlState<T>,
(ValidatorFn | ValidatorFn[] | AbstractControlOptions)?,
(AsyncValidatorFn | AsyncValidatorFn[])?
]
Expand Down
1 change: 1 addition & 0 deletions projects/forms/src/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ export {
AbstractControlOptions,
ValidatorsModel,
Control,
ExtractModelValue,
} from './lib/types';

0 comments on commit e10912a

Please sign in to comment.