Skip to content

Commit

Permalink
feat(forms): export forms utility functions: isFormArray, isFormGroup… (
Browse files Browse the repository at this point in the history
#47718)

This commit exports existing utility functions to check for control instances:
isFormControl, isFormGroup, isFormRecord, isFormArray
Those are useful when implementing validators that use the specifics of one of those control types.
To narrow down the type to what it actually is, we can now use the util functions in validators:

```
export const myArrayValidator: ValidatorFn = (control) => {
  if (!isFormArray(control)) { return null; }

  // now you can use FormArray-specific members, e.g.:
  if (control.controls.every(c => !!c.value) {
    return { myerror: true }
  } else { return null; }
}
```

PR Close #47718
  • Loading branch information
fmalcher authored and thePunderWoman committed Oct 10, 2022
1 parent c0c7efa commit a8569e3
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 3 deletions.
12 changes: 12 additions & 0 deletions goldens/public-api/forms/index.md
Expand Up @@ -559,6 +559,18 @@ export class FormsModule {
static ɵmod: i0.ɵɵNgModuleDeclaration<FormsModule, [typeof i1_2.NgModel, typeof i2_2.NgModelGroup, typeof i3_2.NgForm], never, [typeof i4_2InternalFormsSharedModule, typeof i1_2.NgModel, typeof i2_2.NgModelGroup, typeof i3_2.NgForm]>;
}

// @public
export const isFormArray: (control: unknown) => control is FormArray<any>;

// @public
export const isFormControl: (control: unknown) => control is FormControl<any>;

// @public
export const isFormGroup: (control: unknown) => control is FormGroup<any>;

// @public
export const isFormRecord: (control: unknown) => control is FormRecord<AbstractControl<any, any>>;

// @public
export class MaxLengthValidator extends AbstractValidatorDirective {
maxlength: string | number | null;
Expand Down
6 changes: 3 additions & 3 deletions packages/forms/src/forms.ts
Expand Up @@ -43,9 +43,9 @@ export {SelectMultipleControlValueAccessor, ɵNgSelectMultipleOption} from './di
export {AsyncValidator, AsyncValidatorFn, CheckboxRequiredValidator, EmailValidator, MaxLengthValidator, MaxValidator, MinLengthValidator, MinValidator, PatternValidator, RequiredValidator, ValidationErrors, Validator, ValidatorFn} from './directives/validators';
export {ControlConfig, FormBuilder, NonNullableFormBuilder, UntypedFormBuilder, ɵElement} from './form_builder';
export {AbstractControl, AbstractControlOptions, FormControlStatus, ɵCoerceStrArrToNumArr, ɵGetProperty, ɵNavigate, ɵRawValue, ɵTokenize, ɵTypedOrUntyped, ɵValue, ɵWriteable} from './model/abstract_model';
export {FormArray, UntypedFormArray, ɵFormArrayRawValue, ɵFormArrayValue} from './model/form_array';
export {FormControl, FormControlOptions, FormControlState, UntypedFormControl, ɵFormControlCtor} from './model/form_control';
export {FormGroup, FormRecord, UntypedFormGroup, ɵFormGroupRawValue, ɵFormGroupValue, ɵOptionalKeys} from './model/form_group';
export {FormArray, isFormArray, UntypedFormArray, ɵFormArrayRawValue, ɵFormArrayValue} from './model/form_array';
export {FormControl, FormControlOptions, FormControlState, isFormControl, UntypedFormControl, ɵFormControlCtor} from './model/form_control';
export {FormGroup, FormRecord, isFormGroup, isFormRecord, UntypedFormGroup, ɵFormGroupRawValue, ɵFormGroupValue, ɵOptionalKeys} from './model/form_group';
export {NG_ASYNC_VALIDATORS, NG_VALIDATORS, Validators} from './validators';
export {VERSION} from './version';

Expand Down
6 changes: 6 additions & 0 deletions packages/forms/src/model/form_array.ts
Expand Up @@ -530,4 +530,10 @@ export type UntypedFormArray = FormArray<any>;

export const UntypedFormArray: UntypedFormArrayCtor = FormArray;

/**
* @description
* Asserts that the given control is an instance of `FormArray`
*
* @publicApi
*/
export const isFormArray = (control: unknown): control is FormArray => control instanceof FormArray;
6 changes: 6 additions & 0 deletions packages/forms/src/model/form_control.ts
Expand Up @@ -561,5 +561,11 @@ export type UntypedFormControl = FormControl<any>;

export const UntypedFormControl: UntypedFormControlCtor = FormControl;

/**
* @description
* Asserts that the given control is an instance of `FormControl`
*
* @publicApi
*/
export const isFormControl = (control: unknown): control is FormControl =>
control instanceof FormControl;
12 changes: 12 additions & 0 deletions packages/forms/src/model/form_group.ts
Expand Up @@ -604,6 +604,12 @@ export type UntypedFormGroup = FormGroup<any>;

export const UntypedFormGroup: UntypedFormGroupCtor = FormGroup;

/**
* @description
* Asserts that the given control is an instance of `FormGroup`
*
* @publicApi
*/
export const isFormGroup = (control: unknown): control is FormGroup => control instanceof FormGroup;

/**
Expand Down Expand Up @@ -706,5 +712,11 @@ export interface FormRecord<TControl> {
getRawValue(): {[key: string]: ɵRawValue<TControl>};
}

/**
* @description
* Asserts that the given control is an instance of `FormRecord`
*
* @publicApi
*/
export const isFormRecord = (control: unknown): control is FormRecord =>
control instanceof FormRecord;

0 comments on commit a8569e3

Please sign in to comment.