@ng-stack/forms
Version:
> provides wrapped Angular's Reactive Forms to write its more strongly typed.
1 lines • 72.5 kB
Source Map (JSON)
{"version":3,"file":"ng-stack-forms.mjs","sources":["../../../projects/forms/src/lib/form-builder.ts","../../../projects/forms/src/lib/input-file.directive.ts","../../../projects/forms/src/lib/ngs-forms.module.ts","../../../projects/forms/src/lib/form-array.ts","../../../projects/forms/src/lib/form-control.ts","../../../projects/forms/src/lib/form-group.ts","../../../projects/forms/src/lib/validators.ts","../../../projects/forms/src/lib/types.ts","../../../projects/forms/src/public-api.ts","../../../projects/forms/src/ng-stack-forms.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\nimport { UntypedFormBuilder as NativeFormBuilder } from '@angular/forms';\n\nimport {\n FbControlConfig,\n AbstractControlOptions,\n ValidatorFn,\n AsyncValidatorFn,\n ValidatorsModel,\n FormControlState,\n} from './types';\nimport { FormGroup } from './form-group';\nimport { FormControl } from './form-control';\nimport { FormArray } from './form-array';\n\n@Injectable()\nexport class FormBuilder extends NativeFormBuilder {\n /**\n * Construct a new `FormGroup` instance.\n *\n * @param controlsConfig A collection of child controls. The key for each child is the name\n * under which it is registered.\n *\n * @param options Configuration options object for the `FormGroup`. The object can\n * have two shapes:\n *\n * 1) `AbstractControlOptions` object (preferred), which consists of:\n * - `validators`: A synchronous validator function, or an array of validator functions\n * - `asyncValidators`: A single async validator or array of async validator functions\n * - `updateOn`: The event upon which the control should be updated (options: 'change' | 'blur' |\n * submit')\n *\n * 2) Legacy configuration object, which consists of:\n * - `validator`: A synchronous validator function, or an array of validator functions\n * - `asyncValidator`: A single async validator or array of async validator functions\n */\n override group<T extends object = any, V extends object = ValidatorsModel>(\n controlsConfig: { [P in keyof T]: FbControlConfig<T[P], V> },\n options: AbstractControlOptions | null = null\n ): FormGroup<T, V> {\n return super.group(controlsConfig, options) as FormGroup<T, V>;\n }\n\n /**\n * @description\n * Construct a new `FormControl` with the given state, validators and options.\n *\n * @param formState Initializes the control with an initial state value, or\n * with an object that contains both a value and a disabled status.\n *\n * @param validatorOrOpts A synchronous validator function, or an array of\n * such functions, or an `AbstractControlOptions` object that contains\n * validation functions and a validation trigger.\n *\n * @param asyncValidator A single async validator or array of async validator\n * functions.\n *\n * ### Initialize a control as disabled\n *\n * The following example returns a control with an initial value in a disabled state.\n```ts\nimport {Component, Inject} from '@angular/core';\nimport {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms';\n// ...\n@Component({\n selector: 'app-disabled-form-control',\n template: `\n <input [formControl]=\"control\" placeholder=\"First\">\n `\n})\nexport class DisabledFormControlComponent {\n control: FormControl;\n\n constructor(private fb: FormBuilder) {\n this.control = fb.control({value: 'my val', disabled: true});\n }\n}\n```\n */\n override control<T = any, V extends object = ValidatorsModel>(\n formState: FormControlState<T> = null,\n validatorOrOpts?:\n | ValidatorFn\n | ValidatorFn[]\n | AbstractControlOptions\n | null,\n asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null\n ): FormControl<T, V> {\n return super.control(\n formState,\n validatorOrOpts,\n asyncValidator\n ) as FormControl<T, V>;\n }\n\n /**\n * Constructs a new `FormArray` from the given array of configurations,\n * validators and options.\n *\n * @param controlsConfig An array of child controls or control configs. Each\n * child control is given an index when it is registered.\n *\n * @param validatorOrOpts A synchronous validator function, or an array of\n * such functions, or an `AbstractControlOptions` object that contains\n * validation functions and a validation trigger.\n *\n * @param asyncValidator A single async validator or array of async validator\n * functions.\n */\n override array<Item = any, V extends object = ValidatorsModel>(\n controlsConfig: FbControlConfig<Item, V>[],\n validatorOrOpts?:\n | ValidatorFn\n | ValidatorFn[]\n | AbstractControlOptions\n | null,\n asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null\n ): FormArray<Item, V> {\n return super.array(\n controlsConfig,\n validatorOrOpts,\n asyncValidator\n ) as FormArray<Item, V>;\n }\n}\n","import {\n Directive,\n ElementRef,\n Renderer2,\n HostListener,\n forwardRef,\n Input,\n Output,\n EventEmitter,\n HostBinding,\n} from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\n@Directive({\n selector: `\n input[type=file][ngModel],\n input[type=file][formControl],\n input[type=file][formControlName]`,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => InputFileDirective),\n multi: true,\n },\n ],\n})\nexport class InputFileDirective implements ControlValueAccessor {\n private _multiple: boolean | string | undefined;\n\n @HostBinding('attr.multiple')\n @Input()\n get multiple(): boolean | string | undefined {\n if (\n this._multiple !== undefined &&\n this._multiple !== false &&\n this._multiple !== 'false'\n ) {\n return '';\n } else {\n return undefined;\n }\n }\n\n set multiple(value: boolean | string | undefined) {\n this._multiple = value;\n }\n @HostBinding('attr.preserveValue') @Input() preserveValue: boolean | string;\n @Output() select = new EventEmitter<File[]>();\n private onChange = (value: FormData) => {};\n private onTouched = () => {};\n\n constructor(private elementRef: ElementRef, private renderer: Renderer2) {}\n\n /**\n * Callback function that should be called when\n * the control's value changes in the UI.\n */\n @HostListener('change', ['$event'])\n callOnChange(event: any) {\n this.onTouched();\n const files = Array.from<File>(this.elementRef.nativeElement.files);\n const formData = new FormData();\n\n let formInputName = this.elementRef.nativeElement.name || 'uploadFile';\n if (\n this.multiple !== undefined &&\n this.multiple !== false &&\n this.multiple !== 'false'\n ) {\n formInputName += '[]';\n }\n files.forEach((file) => formData.append(formInputName, file));\n\n this.onChange(formData);\n this.select.next(files);\n if (\n this.preserveValue === undefined ||\n this.preserveValue === false ||\n this.preserveValue === 'false'\n ) {\n event.target.value = null;\n }\n }\n\n /**\n * Writes a new value to the element.\n * This method will be called by the forms API to write\n * to the view when programmatic (model -> view) changes are requested.\n *\n * See: [ControlValueAccessor](https://angular.io/api/forms/ControlValueAccessor#members)\n */\n writeValue(fileList: FileList): void {\n if (fileList && !(fileList instanceof FileList)) {\n throw new TypeError(\n 'Value for input[type=file] must be an instance of FileList'\n );\n }\n this.renderer.setProperty(this.elementRef.nativeElement, 'files', fileList);\n }\n\n /**\n * Registers a callback function that should be called when\n * the control's value changes in the UI.\n *\n * This is called by the forms API on initialization so it can update\n * the form model when values propagate from the view (view -> model).\n */\n registerOnChange(fn: () => void): void {\n this.onChange = fn;\n }\n\n /**\n * Registers a callback function that should be called when the control receives a change event.\n * This is called by the forms API on initialization so it can update the form model on change.\n */\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n}\n","import { NgModule } from '@angular/core';\nimport { ReactiveFormsModule } from '@angular/forms';\n\nimport { FormBuilder } from './form-builder';\nimport { InputFileDirective } from './input-file.directive';\n\n@NgModule({\n declarations: [InputFileDirective],\n exports: [ReactiveFormsModule, InputFileDirective],\n providers: [FormBuilder],\n})\nexport class NgsFormsModule {}\n","import { UntypedFormArray as NativeFormArray } from '@angular/forms';\n\nimport { Observable } from 'rxjs';\n\nimport {\n ControlType,\n Status,\n ValidatorFn,\n AsyncValidatorFn,\n ValidatorsModel,\n ValidationErrors,\n AbstractControlOptions,\n StringKeys,\n ExtractModelValue,\n FormControlState,\n} from './types';\n\nexport class FormArray<\n Item = any,\n V extends object = ValidatorsModel\n> extends NativeFormArray {\n override readonly value: ExtractModelValue<Item>[];\n override readonly valueChanges: Observable<ExtractModelValue<Item>[]>;\n override readonly status: Status;\n override readonly statusChanges: Observable<Status>;\n override readonly errors: ValidationErrors<V> | null;\n\n /**\n * Creates a new `FormArray` instance.\n *\n * @param controls An array of child controls. Each child control is given an index\n * where it is registered.\n *\n * @param validatorOrOpts A synchronous validator function, or an array of\n * such functions, or an `AbstractControlOptions` object that contains validation functions\n * and a validation trigger.\n *\n * @param asyncValidator A single async validator or array of async validator functions\n *\n */\n constructor(\n public override controls: ControlType<Item, V>[],\n validatorOrOpts?:\n | ValidatorFn\n | ValidatorFn[]\n | AbstractControlOptions\n | null,\n asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null\n ) {\n super(controls, validatorOrOpts, asyncValidator);\n }\n\n /**\n * Get the Control at the given `index` in the array.\n *\n * @param index Index in the array to retrieve the control\n */\n override at(index: number) {\n return super.at(index) as ControlType<Item, V>;\n }\n\n /**\n * Insert a new Control at the end of the array.\n *\n * @param control Form control to be inserted\n */\n override push(control: ControlType<Item, V>) {\n return super.push(control);\n }\n\n /**\n * Insert a new Control at the given `index` in the array.\n *\n * @param index Index in the array to insert the control\n * @param control Form control to be inserted\n */\n override insert(index: number, control: ControlType<Item, V>) {\n return super.insert(index, control);\n }\n\n /**\n * Replace an existing control.\n *\n * @param index Index in the array to replace the control\n * @param control The Control control to replace the existing control\n */\n override setControl(index: number, control: ControlType<Item, V>) {\n return super.setControl(index, control);\n }\n\n /**\n * Sets the value of the `FormArray`. It accepts an array that matches\n * the structure of the control.\n *\n * This method performs strict checks, and throws an error if you try\n * to set the value of a control that doesn't exist or if you exclude the\n * value of a control.\n *\n * ### Set the values for the controls in the form array\n *\n```ts\nconst arr = new FormArray([\n new FormControl(),\n new FormControl()\n]);\nconsole.log(arr.value); // [null, null]\n\narr.setValue(['Nancy', 'Drew']);\nconsole.log(arr.value); // ['Nancy', 'Drew']\n```\n *\n * @param value Array of values for the controls\n * @param options Configure options that determine how the control propagates changes and\n * emits events after the value changes\n *\n * * `onlySelf`: When true, each change only affects this control, and not its parent. Default\n * is false.\n * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and\n * `valueChanges`\n * observables emit events with the latest status and value when the control value is updated.\n * When false, no events are emitted.\n * The configuration options are passed to the\n * [updateValueAndValidity](https://angular.io/api/forms/AbstractControl#updateValueAndValidity) method.\n */\n override setValue(\n value: ExtractModelValue<Item>[],\n options: { onlySelf?: boolean; emitEvent?: boolean } = {}\n ) {\n return super.setValue(value, options);\n }\n\n /**\n * Patches the value of the `FormArray`. It accepts an array that matches the\n * structure of the control, and does its best to match the values to the correct\n * controls in the group.\n *\n * It accepts both super-sets and sub-sets of the array without throwing an error.\n *\n * ### Patch the values for controls in a form array\n *\n```ts\nconst arr = new FormArray([\n new FormControl(),\n new FormControl()\n]);\nconsole.log(arr.value); // [null, null]\n\narr.patchValue(['Nancy']);\nconsole.log(arr.value); // ['Nancy', null]\n```\n *\n * @param value Array of latest values for the controls\n * @param options Configure options that determine how the control propagates changes and\n * emits events after the value changes\n *\n * * `onlySelf`: When true, each change only affects this control, and not its parent. Default\n * is false.\n * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and\n * `valueChanges`\n * observables emit events with the latest status and value when the control value is updated.\n * When false, no events are emitted.\n * The configuration options are passed to the\n * [updateValueAndValidity](https://angular.io/api/forms/AbstractControl#updateValueAndValidity) method.\n */\n override patchValue(\n value: ExtractModelValue<Item>[],\n options: { onlySelf?: boolean; emitEvent?: boolean } = {}\n ) {\n return super.patchValue(value, options);\n }\n\n /**\n * Resets the `FormArray` and all descendants are marked `pristine` and `untouched`, and the\n * value of all descendants to null or null maps.\n *\n * You reset to a specific form state by passing in an array of states\n * that matches the structure of the control. The state is a standalone value\n * or a form state object with both a value and a disabled status.\n *\n * ### Reset the values in a form array\n *\n```ts\nconst arr = new FormArray([\n new FormControl(),\n new FormControl()\n]);\narr.reset(['name', 'last name']);\n\nconsole.log(this.arr.value); // ['name', 'last name']\n```\n *\n * ### Reset the values in a form array and the disabled status for the first control\n *\n```\nthis.arr.reset([\n {value: 'name', disabled: true},\n 'last'\n]);\n\nconsole.log(this.arr.value); // ['name', 'last name']\nconsole.log(this.arr.get(0).status); // 'DISABLED'\n```\n *\n * @param value Array of values for the controls\n * @param options Configure options that determine how the control propagates changes and\n * emits events after the value changes\n *\n * * `onlySelf`: When true, each change only affects this control, and not its parent. Default\n * is false.\n * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and\n * `valueChanges`\n * observables emit events with the latest status and value when the control is reset.\n * When false, no events are emitted.\n * The configuration options are passed to the\n * [updateValueAndValidity](https://angular.io/api/forms/AbstractControl#updateValueAndValidity) method.\n */\n override reset(\n value: FormControlState<Item>[] = [],\n options: { onlySelf?: boolean; emitEvent?: boolean } = {}\n ) {\n return super.reset(value, options);\n }\n\n /**\n * The aggregate value of the array, including any disabled controls.\n *\n * Reports all values regardless of disabled status.\n * For enabled controls only, the `value` property is the best way to get the value of the array.\n */\n override getRawValue() {\n return super.getRawValue() as ExtractModelValue<Item>[];\n }\n\n /**\n * Sets the synchronous validators that are active on this control. Calling\n * this overwrites any existing sync validators.\n */\n override setValidators(newValidator: ValidatorFn | ValidatorFn[] | null) {\n return super.setValidators(newValidator);\n }\n\n /**\n * Sets the async validators that are active on this control. Calling this\n * overwrites any existing async validators.\n */\n override setAsyncValidators(\n newValidator: AsyncValidatorFn | AsyncValidatorFn[] | null\n ) {\n return super.setAsyncValidators(newValidator);\n }\n\n /**\n * Sets errors on a form control when running validations manually, rather than automatically.\n *\n * Calling `setErrors` also updates the validity of the parent control.\n *\n * ### Manually set the errors for a control\n *\n * ```ts\n * const login = new FormControl('someLogin');\n * login.setErrors({\n * notUnique: true\n * });\n *\n * expect(login.valid).toEqual(false);\n * expect(login.errors).toEqual({ notUnique: true });\n *\n * login.setValue('someOtherLogin');\n *\n * expect(login.valid).toEqual(true);\n * ```\n */\n override setErrors(\n errors: ValidationErrors | null,\n opts: { emitEvent?: boolean } = {}\n ) {\n return super.setErrors(errors, opts);\n }\n\n /**\n * Reports error data for the control with the given controlName.\n *\n * @param errorCode The code of the error to check\n * @param controlName A control name that designates how to move from the current control\n * to the control that should be queried for errors.\n *\n * For example, for the following `FormGroup`:\n *\n```ts\nform = new FormGroup({\n address: new FormGroup({ street: new FormControl() })\n});\n```\n *\n * The controlName to the 'street' control from the root form would be 'address' -> 'street'.\n *\n * It can be provided to this method in combination with `get()` method:\n *\n```ts\nform.get('address').getError('someErrorCode', 'street');\n```\n *\n * @returns error data for that particular error. If the control or error is not present,\n * null is returned.\n */\n override getError<P extends StringKeys<V>, K extends StringKeys<Item>>(\n errorCode: P,\n controlName?: K\n ) {\n return super.getError(errorCode, controlName) as V[P] | null;\n }\n\n /**\n * Reports whether the control with the given controlName has the error specified.\n *\n * @param errorCode The code of the error to check\n * @param controlName A control name that designates how to move from the current control\n * to the control that should be queried for errors.\n *\n * For example, for the following `FormGroup`:\n *\n```ts\nform = new FormGroup({\n address: new FormGroup({ street: new FormControl() })\n});\n```\n *\n * The controlName to the 'street' control from the root form would be 'address' -> 'street'.\n *\n * It can be provided to this method in combination with `get()` method:\n```ts\nform.get('address').hasError('someErrorCode', 'street');\n```\n *\n * If no controlName is given, this method checks for the error on the current control.\n *\n * @returns whether the given error is present in the control at the given controlName.\n *\n * If the control is not present, false is returned.\n */\n override hasError<P extends StringKeys<V>, K extends StringKeys<Item>>(\n errorCode: P,\n controlName?: K\n ) {\n return super.hasError(errorCode, controlName);\n }\n}\n","import { UntypedFormControl as NativeFormControl } from '@angular/forms';\n\nimport { Observable } from 'rxjs';\n\nimport {\n Status,\n ValidationErrors,\n StringKeys,\n ValidatorFn,\n AsyncValidatorFn,\n AbstractControlOptions,\n ValidatorsModel,\n ExtractControlValue,\n FormControlState,\n} from './types';\n\nexport class FormControl<T = any, V extends object = ValidatorsModel> extends NativeFormControl {\n override readonly value: ExtractControlValue<T>;\n override readonly valueChanges: Observable<ExtractControlValue<T>>;\n override readonly status: Status;\n override readonly statusChanges: Observable<Status>;\n override readonly errors: ValidationErrors<V> | null;\n\n /**\n * Creates a new `FormControl` instance.\n *\n * @param formState Initializes the control with an initial value,\n * or an object that defines the initial value and disabled state.\n *\n * @param validatorOrOpts A synchronous validator function, or an array of\n * such functions, or an `AbstractControlOptions` object that contains validation functions\n * and a validation trigger.\n *\n * @param asyncValidator A single async validator or array of async validator functions\n *\n */\n constructor(\n formState: FormControlState<T> = null,\n validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null,\n asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null\n ) {\n super(formState, validatorOrOpts, asyncValidator);\n }\n\n /**\n * Sets a new value for the form control.\n *\n * @param value The new value for the control.\n * @param options Configuration options that determine how the control proopagates changes\n * and emits events when the value changes.\n * The configuration options are passed to the\n * [updateValueAndValidity](https://angular.io/api/forms/AbstractControl#updateValueAndValidity) method.\n *\n * * `onlySelf`: When true, each change only affects this control, and not its parent. Default is\n * false.\n * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and\n * `valueChanges`\n * observables emit events with the latest status and value when the control value is updated.\n * When false, no events are emitted.\n * * `emitModelToViewChange`: When true or not supplied (the default), each change triggers an\n * `onChange` event to\n * update the view.\n * * `emitViewToModelChange`: When true or not supplied (the default), each change triggers an\n * `ngModelChange`\n * event to update the model.\n *\n */\n override setValue(\n value: ExtractControlValue<T>,\n options: {\n onlySelf?: boolean;\n emitEvent?: boolean;\n emitModelToViewChange?: boolean;\n emitViewToModelChange?: boolean;\n } = {}\n ) {\n return super.setValue(value, options);\n }\n\n /**\n * Patches the value of a control.\n *\n * This function is functionally the same as [setValue](https://angular.io/api/forms/FormControl#setValue) at this level.\n * It exists for symmetry with [patchValue](https://angular.io/api/forms/FormGroup#patchValue) on `FormGroups` and\n * `FormArrays`, where it does behave differently.\n *\n * See also: `setValue` for options\n */\n override patchValue(\n value: ExtractControlValue<T>,\n options: {\n onlySelf?: boolean;\n emitEvent?: boolean;\n emitModelToViewChange?: boolean;\n emitViewToModelChange?: boolean;\n } = {}\n ) {\n return super.patchValue(value, options);\n }\n\n /**\n * Resets the form control, marking it `pristine` and `untouched`, and setting\n * the value to null.\n *\n * @param formState Resets the control with an initial value,\n * or an object that defines the initial value and disabled state.\n *\n * @param options Configuration options that determine how the control propagates changes\n * and emits events after the value changes.\n *\n * * `onlySelf`: When true, each change only affects this control, and not its parent. Default is\n * false.\n * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and\n * `valueChanges`\n * observables emit events with the latest status and value when the control is reset.\n * When false, no events are emitted.\n *\n */\n override reset(\n formState: FormControlState<T> = null,\n options: {\n onlySelf?: boolean;\n emitEvent?: boolean;\n } = {}\n ) {\n return super.reset(formState, options);\n }\n\n /**\n * In `FormControl`, this method always returns `null`.\n */\n override get(): null {\n return null;\n }\n\n /**\n * Sets the synchronous validators that are active on this control. Calling\n * this overwrites any existing sync validators.\n */\n override setValidators(newValidator: ValidatorFn | ValidatorFn[] | null) {\n return super.setValidators(newValidator);\n }\n\n /**\n * Sets the async validators that are active on this control. Calling this\n * overwrites any existing async validators.\n */\n override setAsyncValidators(newValidator: AsyncValidatorFn | AsyncValidatorFn[] | null) {\n return super.setAsyncValidators(newValidator);\n }\n\n /**\n * Sets errors on a form control when running validations manually, rather than automatically.\n *\n * Calling `setErrors` also updates the validity of the parent control.\n *\n * ### Manually set the errors for a control\n *\n * ```ts\n * const login = new FormControl('someLogin');\n * login.setErrors({\n * notUnique: true\n * });\n *\n * expect(login.valid).toEqual(false);\n * expect(login.errors).toEqual({ notUnique: true });\n *\n * login.setValue('someOtherLogin');\n *\n * expect(login.valid).toEqual(true);\n * ```\n */\n override setErrors(errors: ValidationErrors | null, opts: { emitEvent?: boolean } = {}) {\n return super.setErrors(errors, opts);\n }\n\n /**\n * Reports error data for the current control.\n *\n * @param errorCode The code of the error to check.\n *\n * @returns error data for that particular error. If an error is not present,\n * null is returned.\n */\n override getError<K extends StringKeys<V> = any>(errorCode: K) {\n return super.getError(errorCode) as V[K] | null;\n }\n\n /**\n * Reports whether the current control has the error specified.\n *\n * @param errorCode The code of the error to check.\n *\n * @returns whether the given error is present in the current control.\n *\n * If an error is not present, false is returned.\n */\n override hasError<K extends StringKeys<V> = any>(errorCode: K) {\n return super.hasError(errorCode);\n }\n}\n","import { UntypedFormGroup as NativeFormGroup } from '@angular/forms';\n\nimport { Observable } from 'rxjs';\n\nimport {\n Status,\n StringKeys,\n ValidatorFn,\n AsyncValidatorFn,\n ValidatorsModel,\n ValidationErrors,\n AbstractControlOptions,\n ControlType,\n ExtractGroupValue,\n} from './types';\n\nexport class FormGroup<\n T extends object = any,\n V extends object = ValidatorsModel\n> extends NativeFormGroup {\n override readonly value: ExtractGroupValue<T>;\n override readonly valueChanges: Observable<ExtractGroupValue<T>>;\n override readonly status: Status;\n override readonly statusChanges: Observable<Status>;\n override readonly errors: ValidationErrors<V> | null;\n\n /**\n * Creates a new `FormGroup` instance.\n *\n * @param controls A collection of child controls. The key for each child is the name\n * under which it is registered.\n *\n * @param validatorOrOpts A synchronous validator function, or an array of\n * such functions, or an `AbstractControlOptions` object that contains validation functions\n * and a validation trigger.\n *\n * @param asyncValidator A single async validator or array of async validator functions\n *\n * @todo Chechout how to respect optional and require properties modifyers for the controls.\n */\n constructor(\n public override controls: { [P in keyof T]: ControlType<T[P], V> },\n validatorOrOpts?:\n | ValidatorFn\n | ValidatorFn[]\n | AbstractControlOptions\n | null,\n asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null\n ) {\n super(controls, validatorOrOpts, asyncValidator);\n }\n\n /**\n * Registers a control with the group's list of controls.\n *\n * This method does not update the value or validity of the control.\n * Use [addControl](https://angular.io/api/forms/FormGroup#addControl) instead.\n *\n * @param name The control name to register in the collection\n * @param control Provides the control for the given name\n */\n override registerControl<\n K extends StringKeys<T>,\n CV extends object = ValidatorsModel\n >(name: K, control: ControlType<T[K], CV>) {\n return super.registerControl(name, control) as ControlType<T[K], CV>;\n }\n\n /**\n * Add a control to this group.\n *\n * This method also updates the value and validity of the control.\n *\n * @param name The control name to add to the collection\n * @param control Provides the control for the given name\n */\n override addControl<\n K extends StringKeys<T>,\n CV extends object = ValidatorsModel\n >(name: K, control: ControlType<T[K], CV>) {\n return super.addControl(name, control);\n }\n\n /**\n * Remove a control from this group.\n *\n * @param name The control name to remove from the collection\n */\n override removeControl<K extends StringKeys<T>>(name: K) {\n return super.removeControl(name);\n }\n\n /**\n * Replace an existing control.\n *\n * @param name The control name to replace in the collection\n * @param control Provides the control for the given name\n */\n override setControl<\n K extends StringKeys<T>,\n CV extends object = ValidatorsModel\n >(name: K, control: ControlType<T[K], CV>) {\n return super.setControl(name, control);\n }\n\n /**\n * Check whether there is an enabled control with the given name in the group.\n *\n * Reports false for disabled controls. If you'd like to check for existence in the group\n * only, use [get](https://angular.io/api/forms/AbstractControl#get) instead.\n *\n * @param name The control name to check for existence in the collection\n *\n * @returns false for disabled controls, true otherwise.\n */\n override contains<K extends StringKeys<T>>(name: K) {\n return super.contains(name);\n }\n\n /**\n * Sets the value of the `FormGroup`. It accepts an object that matches\n * the structure of the group, with control names as keys.\n *\n * ### Set the complete value for the form group\n *\n```ts\nconst form = new FormGroup({\n first: new FormControl(),\n last: new FormControl()\n});\n\nconsole.log(form.value); // {first: null, last: null}\n\nform.setValue({first: 'Nancy', last: 'Drew'});\nconsole.log(form.value); // {first: 'Nancy', last: 'Drew'}\n```\n *\n * @throws When strict checks fail, such as setting the value of a control\n * that doesn't exist or if you excluding the value of a control.\n *\n * @param value The new value for the control that matches the structure of the group.\n * @param options Configuration options that determine how the control propagates changes\n * and emits events after the value changes.\n * The configuration options are passed to the\n * [updateValueAndValidity](https://angular.io/api/forms/AbstractControl#updateValueAndValidity) method.\n *\n * * `onlySelf`: When true, each change only affects this control, and not its parent. Default is\n * false.\n * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and\n * `valueChanges`\n * observables emit events with the latest status and value when the control value is updated.\n * When false, no events are emitted.\n */\n override setValue(\n value: ExtractGroupValue<T>,\n options: { onlySelf?: boolean; emitEvent?: boolean } = {}\n ) {\n return super.setValue(value, options);\n }\n\n /**\n * Patches the value of the `FormGroup`. It accepts an object with control\n * names as keys, and does its best to match the values to the correct controls\n * in the group.\n *\n * It accepts both super-sets and sub-sets of the group without throwing an error.\n *\n * ### Patch the value for a form group\n *\n```ts\nconst form = new FormGroup({\n first: new FormControl(),\n last: new FormControl()\n});\nconsole.log(form.value); // {first: null, last: null}\n\nform.patchValue({first: 'Nancy'});\nconsole.log(form.value); // {first: 'Nancy', last: null}\n```\n *\n * @param value The object that matches the structure of the group.\n * @param options Configuration options that determine how the control propagates changes and\n * emits events after the value is patched.\n * * `onlySelf`: When true, each change only affects this control and not its parent. Default is\n * true.\n * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and\n * `valueChanges`\n * observables emit events with the latest status and value when the control value is updated.\n * When false, no events are emitted.\n * The configuration options are passed to the\n * [updateValueAndValidity](https://angular.io/api/forms/AbstractControl#updateValueAndValidity) method.\n */\n override patchValue(\n value: Partial<ExtractGroupValue<T>>,\n options: { onlySelf?: boolean; emitEvent?: boolean } = {}\n ) {\n return super.patchValue(value, options);\n }\n\n /**\n * Resets the `FormGroup`, marks all descendants are marked `pristine` and `untouched`, and\n * the value of all descendants to null.\n *\n * You reset to a specific form state by passing in a map of states\n * that matches the structure of your form, with control names as keys. The state\n * is a standalone value or a form state object with both a value and a disabled\n * status.\n *\n * @param formState Resets the control with an initial value,\n * or an object that defines the initial value and disabled state.\n *\n * @param options Configuration options that determine how the control propagates changes\n * and emits events when the group is reset.\n * * `onlySelf`: When true, each change only affects this control, and not its parent. Default is\n * false.\n * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and\n * `valueChanges`\n * observables emit events with the latest status and value when the control is reset.\n * When false, no events are emitted.\n * The configuration options are passed to the\n * [updateValueAndValidity](https://angular.io/api/forms/AbstractControl#updateValueAndValidity) method.\n *\n *\n * ### Reset the form group values\n *\n```ts\nconst form = new FormGroup({\n first: new FormControl('first name'),\n last: new FormControl('last name')\n});\n\nconsole.log(form.value); // {first: 'first name', last: 'last name'}\n\nform.reset({ first: 'name', last: 'last name' });\n\nconsole.log(form.value); // {first: 'name', last: 'last name'}\n```\n *\n * ### Reset the form group values and disabled status\n *\n```ts\nconst form = new FormGroup({\n first: new FormControl('first name'),\n last: new FormControl('last name')\n});\n\nform.reset({\n first: {value: 'name', disabled: true},\n last: 'last'\n});\n\nconsole.log(this.form.value); // {first: 'name', last: 'last name'}\nconsole.log(this.form.get('first').status); // 'DISABLED'\n```\n */\n override reset(\n value: ExtractGroupValue<T> = {} as any,\n options: { onlySelf?: boolean; emitEvent?: boolean } = {}\n ) {\n return super.reset(value, options);\n }\n\n /**\n * The aggregate value of the `FormGroup`, including any disabled controls.\n *\n * Retrieves all values regardless of disabled status.\n * The `value` property is the best way to get the value of the group, because\n * it excludes disabled controls in the `FormGroup`.\n */\n override getRawValue() {\n return super.getRawValue() as ExtractGroupValue<T>;\n }\n\n /**\n * Retrieves a child control given the control's name.\n *\n * ### Retrieve a nested control\n *\n * For example, to get a `name` control nested within a `person` sub-group:\n```ts\nthis.form.get('person').get('name');\n```\n */\n override get<K extends StringKeys<T>, CV extends object = ValidatorsModel>(\n controlName: K\n ): ControlType<T[K], CV> | null {\n return super.get(controlName) as ControlType<T[K], CV> | null;\n }\n\n /**\n * Sets the synchronous validators that are active on this control. Calling\n * this overwrites any existing sync validators.\n */\n override setValidators(newValidator: ValidatorFn | ValidatorFn[] | null) {\n return super.setValidators(newValidator);\n }\n\n /**\n * Sets the async validators that are active on this control. Calling this\n * overwrites any existing async validators.\n */\n override setAsyncValidators(\n newValidator: AsyncValidatorFn | AsyncValidatorFn[] | null\n ) {\n return super.setAsyncValidators(newValidator);\n }\n\n /**\n * Sets errors on a form control when running validations manually, rather than automatically.\n *\n * Calling `setErrors` also updates the validity of the parent control.\n *\n * ### Manually set the errors for a control\n *\n * ```ts\n * const login = new FormControl('someLogin');\n * login.setErrors({\n * notUnique: true\n * });\n *\n * expect(login.valid).toEqual(false);\n * expect(login.errors).toEqual({ notUnique: true });\n *\n * login.setValue('someOtherLogin');\n *\n * expect(login.valid).toEqual(true);\n * ```\n */\n override setErrors(\n errors: ValidationErrors | null,\n opts: { emitEvent?: boolean } = {}\n ) {\n return super.setErrors(errors, opts);\n }\n\n /**\n * Reports error data for the control with the given controlName.\n *\n * @param errorCode The code of the error to check\n * @param controlName A control name that designates how to move from the current control\n * to the control that should be queried for errors.\n *\n * For example, for the following `FormGroup`:\n *\n```ts\nform = new FormGroup({\n address: new FormGroup({ street: new FormControl() })\n});\n```\n *\n * The controlName to the 'street' control from the root form would be 'address' -> 'street'.\n *\n * It can be provided to this method in combination with `get()` method:\n *\n```ts\nform.get('address').getError('someErrorCode', 'street');\n```\n *\n * @returns error data for that particular error. If the control or error is not present,\n * null is returned.\n */\n override getError<P extends StringKeys<V>, K extends StringKeys<T>>(\n errorCode: P,\n controlName?: K\n ) {\n return super.getError(errorCode, controlName) as V[P] | null;\n }\n\n /**\n * Reports whether the control with the given controlName has the error specified.\n *\n * @param errorCode The code of the error to check\n * @param controlName A control name that designates how to move from the current control\n * to the control that should be queried for errors.\n *\n * For example, for the following `FormGroup`:\n *\n```ts\nform = new FormGroup({\n address: new FormGroup({ street: new FormControl() })\n});\n```\n *\n * The controlName to the 'street' control from the root form would be 'address' -> 'street'.\n *\n * It can be provided to this method in combination with `get()` method:\n```ts\nform.get('address').hasError('someErrorCode', 'street');\n```\n *\n * If no controlName is given, this method checks for the error on the current control.\n *\n * @returns whether the given error is present in the control at the given controlName.\n *\n * If the control is not present, false is returned.\n */\n override hasError<P extends StringKeys<V>, K extends StringKeys<T>>(\n errorCode: P,\n controlName?: K\n ) {\n return super.hasError(errorCode, controlName);\n }\n}\n","import { Validators as NativeValidators, AbstractControl } from '@angular/forms';\n\nimport { ValidatorFn, ValidationErrors, AsyncValidatorFn } from './types';\nimport { FormControl } from './form-control';\n\n// Next flag used because of this https://github.com/ng-packagr/ng-packagr/issues/696#issuecomment-373487183\n// @dynamic\n/**\n * Provides a set of built-in validators that can be used by form controls.\n *\n * A validator is a function that processes a `FormControl` or collection of\n * controls and returns an error map or null. A null map means that validation has passed.\n *\n * See also [Form Validation](https://angular.io/guide/form-validation).\n */\nexport class Validators extends NativeValidators {\n /**\n * Validator that requires the control's value to be greater than or equal to the provided number.\n * The validator exists only as a function and not as a directive.\n *\n * ### Validate against a minimum of 3\n *\n * ```ts\n * const control = new FormControl(2, Validators.min(3));\n *\n * console.log(control.errors); // {min: {min: 3, actual: 2}}\n * ```\n *\n * @returns A validator function that returns an error map with the\n * `min` property if the validation check fails, otherwise `null`.\n *\n */\n static override min(min: number) {\n return super.min(min) as ValidatorFn<{ min: { min: number; actual: number } }>;\n }\n\n /**\n * Validator that requires the control's value to be less than or equal to the provided number.\n * The validator exists only as a function and not as a directive.\n *\n * ### Validate against a maximum of 15\n *\n * ```ts\n * const control = new FormControl(16, Validators.max(15));\n *\n * console.log(control.errors); // {max: {max: 15, actual: 16}}\n * ```\n *\n * @returns A validator function that returns an error map with the\n * `max` property if the validation check fails, otherwise `null`.\n *\n */\n static override max(max: number) {\n return super.max(max) as ValidatorFn<{ max: { max: number; actual: number } }>;\n }\n\n /**\n * Validator that requires the control have a non-empty value.\n *\n * ### Validate that the field is non-empty\n *\n * ```ts\n * const control = new FormControl('', Validators.required);\n *\n * console.log(control.errors); // {required: true}\n * ```\n *\n * @returns An error map with the `required` property\n * if the validation check fails, otherwise `null`.\n *\n */\n static override required(control: AbstractControl) {\n return super.required(control) as ValidationErrors<{ required: true }> | null;\n }\n\n /**\n * Validator that requires the control's value be true. This validator is commonly\n * used for required checkboxes.\n *\n * ### Validate that the field value is true\n *\n * ```typescript\n * const control = new FormControl('', Validators.requiredTrue);\n *\n * console.log(control.errors); // {required: true}\n * ```\n *\n * @returns An error map that contains the `required` property\n * set to `true` if the validation check fails, otherwise `null`.\n */\n static override requiredTrue(control: AbstractControl) {\n return super.requiredTrue(control) as ValidationErrors<{ required: true }> | null;\n }\n\n /**\n * Validator that requires the control's value pass an email validation test.\n *\n * ### Validate that the field matches a valid email pattern\n *\n * ```typescript\n * const control = new FormControl('bad@', Validators.email);\n *\n * console.log(control.errors); // {email: true}\n * ```\n *\n * @returns An error map with the `email` property\n * if the validation check fails, otherwise `null`.\n *\n */\n static override email(control: AbstractControl) {\n return super.email(control) as ValidationErrors<{ email: true }> | null;\n }\n\n /**\n * Validator that requires the length of the control's value to be greater than or equal\n * to the provided minimum length. This validator is also provided by default if you use the\n * the HTML5 `minlength` attribute.\n *\n * ### Validate that the field has a minimum of 3 characters\n *\n * ```typescript\n * const control = new FormControl('ng', Validators.minLength(3));\n *\n * console.log(control.errors); // {minlength: {requiredLength: 3, actualLength: 2}}\n * ```\n *\n * ```html\n * <input minlength=\"5\">\n * ```\n *\n * @returns A validator function that returns an error map with the\n * `minlength` if the validation check fails, otherwise `null`.\n */\n static override minLength(minLength: number) {\n return super.minLength(minLength) as ValidatorFn<{\n minlength: { requiredLength: number; actualLength: number };\n }>;\n }\n\n /**\n * Validator that requires the length of the control's value to be less than or equal\n * to the provided maximum length. This validator is also provided by default if you use the\n * the HTML5 `maxlength` attribute.\n *\n * ### Validate that the field has maximum of 5 characters\n *\n * ```typescript\n * const control = new FormControl('Angular', Validators.maxLength(5));\n *\n * console.log(control.errors); // {maxlength: {requiredLength: 5, actualLength: 7}}\n * ```\n *\n * ```html\n * <input maxlength=\"5\">\n * ```\n *\n * @returns A validator function that returns an error map with the\n * `maxlength` property if the validation check fails, otherwise `null`.\n */\n static override maxLength(maxLength: number) {\n return super.maxLength(maxLength) as ValidatorFn<{\n maxlength: { requiredLength: number; actualLength: number };\n }>;\n }\n\n /**\n * Validator that requires the control's value to match a regex pattern. This validator is also\n * provided by default if you use the HTML5 `pattern` attribute.\n *\n * Note that if a Regexp is provided, the Regexp is used as is to test the values. On the other\n * hand, if a string is passed, the `^` character is prepended and the `$` character is\n * appended to the provided string (if not already present), and the resulting regular\n * expression is used to test the values.\n *\n * ### Validate that the field only contains letters or spaces\n *\n * ```typescript\n * const control = new FormControl('1', Validators.pattern('[a-zA-Z ]*'));\n *\n * console.log(control.errors); // {pattern: {requiredPattern: '^[a-zA-Z ]*$', actualValue: '1'}}\n * ```\n *\n * ```html\n * <input pattern=\"[a-zA-Z ]*\">\n * ```\n *\n * @returns A validator function that returns an error map with the\n * `pattern` property if the validation check fails, otherwise `null`.\n */\n static override pattern(pattern: string | RegExp) {\n return super.pattern(pattern) as ValidatorFn<{\n pattern: { requiredPattern: string; actualValue: string };\n }>;\n }\n\n /**\n * Validator that performs no operation.\n */\n static override nullValidator(control: AbstractControl): null {\n return null;\n }\n\n /**\n * Compose multiple validators into a single function that returns the union\n * of the individual error maps for the provided control.\n *\n * @returns A validator function that returns an error map with the\n * merged error maps of the validators if the validation check fails, otherwise `null`.\n */\n static override compose(validators: null): null;\n static override compose<T extends object = any>(validators: (ValidatorFn | null | undefined)[]): ValidatorFn<T> | null;\n static override compose<T extends object = any>(validators: (ValidatorFn | null | undefined)[] | null): ValidatorFn<T> | null {\n return super.compose(validators as any);\n }\n\n /**\n * Compose multiple async validators into a single function that returns the union\n * of the individual error objects for the provided control.\n *\n * @returns A validator function that returns an error map with the\n * merged error objects of the async validators if the validation check fails, otherwise `null`.\n */\n static override composeAsync<T extends object = any>(validators: (AsyncValidatorFn<T> | null)[]) {\n return super.composeAsync(validators) as AsyncValidatorFn<T> | null;\n }\n\n /**\n * At least one file should be.\n *\n * **Note**: use this validator when `formControl.value` is an instance of `FormData` only.\n */\n static fileRequired(formControl: FormControl<FormData>): ValidationErrors<{ fileRequired: true }> | null {\n if (!(formControl.value instanceof FormData)) {\n return { fileRequired: true };\n }\n\n const files: FormDataEntryValue[] = [];\n formControl.value.forEach((file) => files.push(file));\n\n for (const file of files) {\n if (file instanceof File) {\n return null;\n }\n }\n\n return { fileRequired: true };\n }\n\n /**\n * Minimal number of files.\n *\n * **Note**: use this validator when `formControl.value` is an instance of `FormData` only.\n */\n static filesMinLength(\n minLength: number\n ): ValidatorFn<{ filesMinLength: { requiredLength: number; actualLength: number } }> {\n return (formControl: any) => {\n const value = formControl.value as FormData;\n\n if (minLength < 1) {\n return null;\n }\n\n if (!value || !(value instanceof FormData)) {\n return { filesMinLength: { requiredLength: minLength, actualLength: 0 } };\n }\n\n const files: FormDataEntryValue[] = [];\n value.forEach((file) => files.push(file));\n const len = files.length;\n if (len < minLength) {\n return { filesMinLength: { requiredLength: minLength, actualLength: len } };\n }\n\n return null;\n };\n }\n\n /**\n