UNPKG

287 kBJavaScriptView Raw
1/**
2 * @license Angular v17.3.5
3 * (c) 2010-2024 Google LLC. https://angular.io/
4 * License: MIT
5 */
6
7import * as i0 from '@angular/core';
8import { Directive, InjectionToken, forwardRef, Optional, Inject, ɵisPromise, ɵisSubscribable, ɵRuntimeError, Self, EventEmitter, Input, Host, SkipSelf, booleanAttribute, ChangeDetectorRef, Output, Injectable, inject, NgModule, Version } from '@angular/core';
9import { ɵgetDOM } from '@angular/common';
10import { from, forkJoin } from 'rxjs';
11import { map } from 'rxjs/operators';
12
13/**
14 * Base class for all ControlValueAccessor classes defined in Forms package.
15 * Contains common logic and utility functions.
16 *
17 * Note: this is an *internal-only* class and should not be extended or used directly in
18 * applications code.
19 */
20class BaseControlValueAccessor {
21 constructor(_renderer, _elementRef) {
22 this._renderer = _renderer;
23 this._elementRef = _elementRef;
24 /**
25 * The registered callback function called when a change or input event occurs on the input
26 * element.
27 * @nodoc
28 */
29 this.onChange = (_) => { };
30 /**
31 * The registered callback function called when a blur event occurs on the input element.
32 * @nodoc
33 */
34 this.onTouched = () => { };
35 }
36 /**
37 * Helper method that sets a property on a target element using the current Renderer
38 * implementation.
39 * @nodoc
40 */
41 setProperty(key, value) {
42 this._renderer.setProperty(this._elementRef.nativeElement, key, value);
43 }
44 /**
45 * Registers a function called when the control is touched.
46 * @nodoc
47 */
48 registerOnTouched(fn) {
49 this.onTouched = fn;
50 }
51 /**
52 * Registers a function called when the control value changes.
53 * @nodoc
54 */
55 registerOnChange(fn) {
56 this.onChange = fn;
57 }
58 /**
59 * Sets the "disabled" property on the range input element.
60 * @nodoc
61 */
62 setDisabledState(isDisabled) {
63 this.setProperty('disabled', isDisabled);
64 }
65 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: BaseControlValueAccessor, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
66 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: BaseControlValueAccessor, ngImport: i0 }); }
67}
68i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: BaseControlValueAccessor, decorators: [{
69 type: Directive
70 }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }] });
71/**
72 * Base class for all built-in ControlValueAccessor classes (except DefaultValueAccessor, which is
73 * used in case no other CVAs can be found). We use this class to distinguish between default CVA,
74 * built-in CVAs and custom CVAs, so that Forms logic can recognize built-in CVAs and treat custom
75 * ones with higher priority (when both built-in and custom CVAs are present).
76 *
77 * Note: this is an *internal-only* class and should not be extended or used directly in
78 * applications code.
79 */
80class BuiltInControlValueAccessor extends BaseControlValueAccessor {
81 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: BuiltInControlValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
82 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: BuiltInControlValueAccessor, usesInheritance: true, ngImport: i0 }); }
83}
84i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: BuiltInControlValueAccessor, decorators: [{
85 type: Directive
86 }] });
87/**
88 * Used to provide a `ControlValueAccessor` for form controls.
89 *
90 * See `DefaultValueAccessor` for how to implement one.
91 *
92 * @publicApi
93 */
94const NG_VALUE_ACCESSOR = new InjectionToken(ngDevMode ? 'NgValueAccessor' : '');
95
96const CHECKBOX_VALUE_ACCESSOR = {
97 provide: NG_VALUE_ACCESSOR,
98 useExisting: forwardRef(() => CheckboxControlValueAccessor),
99 multi: true,
100};
101/**
102 * @description
103 * A `ControlValueAccessor` for writing a value and listening to changes on a checkbox input
104 * element.
105 *
106 * @usageNotes
107 *
108 * ### Using a checkbox with a reactive form.
109 *
110 * The following example shows how to use a checkbox with a reactive form.
111 *
112 * ```ts
113 * const rememberLoginControl = new FormControl();
114 * ```
115 *
116 * ```
117 * <input type="checkbox" [formControl]="rememberLoginControl">
118 * ```
119 *
120 * @ngModule ReactiveFormsModule
121 * @ngModule FormsModule
122 * @publicApi
123 */
124class CheckboxControlValueAccessor extends BuiltInControlValueAccessor {
125 /**
126 * Sets the "checked" property on the input element.
127 * @nodoc
128 */
129 writeValue(value) {
130 this.setProperty('checked', value);
131 }
132 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: CheckboxControlValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
133 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]", host: { listeners: { "change": "onChange($event.target.checked)", "blur": "onTouched()" } }, providers: [CHECKBOX_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 }); }
134}
135i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: CheckboxControlValueAccessor, decorators: [{
136 type: Directive,
137 args: [{
138 selector: 'input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]',
139 host: { '(change)': 'onChange($event.target.checked)', '(blur)': 'onTouched()' },
140 providers: [CHECKBOX_VALUE_ACCESSOR]
141 }]
142 }] });
143
144const DEFAULT_VALUE_ACCESSOR = {
145 provide: NG_VALUE_ACCESSOR,
146 useExisting: forwardRef(() => DefaultValueAccessor),
147 multi: true
148};
149/**
150 * We must check whether the agent is Android because composition events
151 * behave differently between iOS and Android.
152 */
153function _isAndroid() {
154 const userAgent = ɵgetDOM() ? ɵgetDOM().getUserAgent() : '';
155 return /android (\d+)/.test(userAgent.toLowerCase());
156}
157/**
158 * @description
159 * Provide this token to control if form directives buffer IME input until
160 * the "compositionend" event occurs.
161 * @publicApi
162 */
163const COMPOSITION_BUFFER_MODE = new InjectionToken(ngDevMode ? 'CompositionEventMode' : '');
164/**
165 * The default `ControlValueAccessor` for writing a value and listening to changes on input
166 * elements. The accessor is used by the `FormControlDirective`, `FormControlName`, and
167 * `NgModel` directives.
168 *
169 * {@searchKeywords ngDefaultControl}
170 *
171 * @usageNotes
172 *
173 * ### Using the default value accessor
174 *
175 * The following example shows how to use an input element that activates the default value accessor
176 * (in this case, a text field).
177 *
178 * ```ts
179 * const firstNameControl = new FormControl();
180 * ```
181 *
182 * ```
183 * <input type="text" [formControl]="firstNameControl">
184 * ```
185 *
186 * This value accessor is used by default for `<input type="text">` and `<textarea>` elements, but
187 * you could also use it for custom components that have similar behavior and do not require special
188 * processing. In order to attach the default value accessor to a custom element, add the
189 * `ngDefaultControl` attribute as shown below.
190 *
191 * ```
192 * <custom-input-component ngDefaultControl [(ngModel)]="value"></custom-input-component>
193 * ```
194 *
195 * @ngModule ReactiveFormsModule
196 * @ngModule FormsModule
197 * @publicApi
198 */
199class DefaultValueAccessor extends BaseControlValueAccessor {
200 constructor(renderer, elementRef, _compositionMode) {
201 super(renderer, elementRef);
202 this._compositionMode = _compositionMode;
203 /** Whether the user is creating a composition string (IME events). */
204 this._composing = false;
205 if (this._compositionMode == null) {
206 this._compositionMode = !_isAndroid();
207 }
208 }
209 /**
210 * Sets the "value" property on the input element.
211 * @nodoc
212 */
213 writeValue(value) {
214 const normalizedValue = value == null ? '' : value;
215 this.setProperty('value', normalizedValue);
216 }
217 /** @internal */
218 _handleInput(value) {
219 if (!this._compositionMode || (this._compositionMode && !this._composing)) {
220 this.onChange(value);
221 }
222 }
223 /** @internal */
224 _compositionStart() {
225 this._composing = true;
226 }
227 /** @internal */
228 _compositionEnd(value) {
229 this._composing = false;
230 this._compositionMode && this.onChange(value);
231 }
232 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: DefaultValueAccessor, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }, { token: COMPOSITION_BUFFER_MODE, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
233 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]", host: { listeners: { "input": "$any(this)._handleInput($event.target.value)", "blur": "onTouched()", "compositionstart": "$any(this)._compositionStart()", "compositionend": "$any(this)._compositionEnd($event.target.value)" } }, providers: [DEFAULT_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 }); }
234}
235i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: DefaultValueAccessor, decorators: [{
236 type: Directive,
237 args: [{
238 selector: 'input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]',
239 // TODO: vsavkin replace the above selector with the one below it once
240 // https://github.com/angular/angular/issues/3011 is implemented
241 // selector: '[ngModel],[formControl],[formControlName]',
242 host: {
243 '(input)': '$any(this)._handleInput($event.target.value)',
244 '(blur)': 'onTouched()',
245 '(compositionstart)': '$any(this)._compositionStart()',
246 '(compositionend)': '$any(this)._compositionEnd($event.target.value)'
247 },
248 providers: [DEFAULT_VALUE_ACCESSOR]
249 }]
250 }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }, { type: undefined, decorators: [{
251 type: Optional
252 }, {
253 type: Inject,
254 args: [COMPOSITION_BUFFER_MODE]
255 }] }] });
256
257function isEmptyInputValue(value) {
258 /**
259 * Check if the object is a string or array before evaluating the length attribute.
260 * This avoids falsely rejecting objects that contain a custom length attribute.
261 * For example, the object {id: 1, length: 0, width: 0} should not be returned as empty.
262 */
263 return value == null ||
264 ((typeof value === 'string' || Array.isArray(value)) && value.length === 0);
265}
266function hasValidLength(value) {
267 // non-strict comparison is intentional, to check for both `null` and `undefined` values
268 return value != null && typeof value.length === 'number';
269}
270/**
271 * @description
272 * An `InjectionToken` for registering additional synchronous validators used with
273 * `AbstractControl`s.
274 *
275 * @see {@link NG_ASYNC_VALIDATORS}
276 *
277 * @usageNotes
278 *
279 * ### Providing a custom validator
280 *
281 * The following example registers a custom validator directive. Adding the validator to the
282 * existing collection of validators requires the `multi: true` option.
283 *
284 * ```typescript
285 * @Directive({
286 * selector: '[customValidator]',
287 * providers: [{provide: NG_VALIDATORS, useExisting: CustomValidatorDirective, multi: true}]
288 * })
289 * class CustomValidatorDirective implements Validator {
290 * validate(control: AbstractControl): ValidationErrors | null {
291 * return { 'custom': true };
292 * }
293 * }
294 * ```
295 *
296 * @publicApi
297 */
298const NG_VALIDATORS = new InjectionToken(ngDevMode ? 'NgValidators' : '');
299/**
300 * @description
301 * An `InjectionToken` for registering additional asynchronous validators used with
302 * `AbstractControl`s.
303 *
304 * @see {@link NG_VALIDATORS}
305 *
306 * @usageNotes
307 *
308 * ### Provide a custom async validator directive
309 *
310 * The following example implements the `AsyncValidator` interface to create an
311 * async validator directive with a custom error key.
312 *
313 * ```typescript
314 * @Directive({
315 * selector: '[customAsyncValidator]',
316 * providers: [{provide: NG_ASYNC_VALIDATORS, useExisting: CustomAsyncValidatorDirective, multi:
317 * true}]
318 * })
319 * class CustomAsyncValidatorDirective implements AsyncValidator {
320 * validate(control: AbstractControl): Promise<ValidationErrors|null> {
321 * return Promise.resolve({'custom': true});
322 * }
323 * }
324 * ```
325 *
326 * @publicApi
327 */
328const NG_ASYNC_VALIDATORS = new InjectionToken(ngDevMode ? 'NgAsyncValidators' : '');
329/**
330 * A regular expression that matches valid e-mail addresses.
331 *
332 * At a high level, this regexp matches e-mail addresses of the format `local-part@tld`, where:
333 * - `local-part` consists of one or more of the allowed characters (alphanumeric and some
334 * punctuation symbols).
335 * - `local-part` cannot begin or end with a period (`.`).
336 * - `local-part` cannot be longer than 64 characters.
337 * - `tld` consists of one or more `labels` separated by periods (`.`). For example `localhost` or
338 * `foo.com`.
339 * - A `label` consists of one or more of the allowed characters (alphanumeric, dashes (`-`) and
340 * periods (`.`)).
341 * - A `label` cannot begin or end with a dash (`-`) or a period (`.`).
342 * - A `label` cannot be longer than 63 characters.
343 * - The whole address cannot be longer than 254 characters.
344 *
345 * ## Implementation background
346 *
347 * This regexp was ported over from AngularJS (see there for git history):
348 * https://github.com/angular/angular.js/blob/c133ef836/src/ng/directive/input.js#L27
349 * It is based on the
350 * [WHATWG version](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address) with
351 * some enhancements to incorporate more RFC rules (such as rules related to domain names and the
352 * lengths of different parts of the address). The main differences from the WHATWG version are:
353 * - Disallow `local-part` to begin or end with a period (`.`).
354 * - Disallow `local-part` length to exceed 64 characters.
355 * - Disallow total address length to exceed 254 characters.
356 *
357 * See [this commit](https://github.com/angular/angular.js/commit/f3f5cf72e) for more details.
358 */
359const EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
360/**
361 * @description
362 * Provides a set of built-in validators that can be used by form controls.
363 *
364 * A validator is a function that processes a `FormControl` or collection of
365 * controls and returns an error map or null. A null map means that validation has passed.
366 *
367 * @see [Form Validation](/guide/form-validation)
368 *
369 * @publicApi
370 */
371class Validators {
372 /**
373 * @description
374 * Validator that requires the control's value to be greater than or equal to the provided number.
375 *
376 * @usageNotes
377 *
378 * ### Validate against a minimum of 3
379 *
380 * ```typescript
381 * const control = new FormControl(2, Validators.min(3));
382 *
383 * console.log(control.errors); // {min: {min: 3, actual: 2}}
384 * ```
385 *
386 * @returns A validator function that returns an error map with the
387 * `min` property if the validation check fails, otherwise `null`.
388 *
389 * @see {@link updateValueAndValidity()}
390 *
391 */
392 static min(min) {
393 return minValidator(min);
394 }
395 /**
396 * @description
397 * Validator that requires the control's value to be less than or equal to the provided number.
398 *
399 * @usageNotes
400 *
401 * ### Validate against a maximum of 15
402 *
403 * ```typescript
404 * const control = new FormControl(16, Validators.max(15));
405 *
406 * console.log(control.errors); // {max: {max: 15, actual: 16}}
407 * ```
408 *
409 * @returns A validator function that returns an error map with the
410 * `max` property if the validation check fails, otherwise `null`.
411 *
412 * @see {@link updateValueAndValidity()}
413 *
414 */
415 static max(max) {
416 return maxValidator(max);
417 }
418 /**
419 * @description
420 * Validator that requires the control have a non-empty value.
421 *
422 * @usageNotes
423 *
424 * ### Validate that the field is non-empty
425 *
426 * ```typescript
427 * const control = new FormControl('', Validators.required);
428 *
429 * console.log(control.errors); // {required: true}
430 * ```
431 *
432 * @returns An error map with the `required` property
433 * if the validation check fails, otherwise `null`.
434 *
435 * @see {@link updateValueAndValidity()}
436 *
437 */
438 static required(control) {
439 return requiredValidator(control);
440 }
441 /**
442 * @description
443 * Validator that requires the control's value be true. This validator is commonly
444 * used for required checkboxes.
445 *
446 * @usageNotes
447 *
448 * ### Validate that the field value is true
449 *
450 * ```typescript
451 * const control = new FormControl('some value', Validators.requiredTrue);
452 *
453 * console.log(control.errors); // {required: true}
454 * ```
455 *
456 * @returns An error map that contains the `required` property
457 * set to `true` if the validation check fails, otherwise `null`.
458 *
459 * @see {@link updateValueAndValidity()}
460 *
461 */
462 static requiredTrue(control) {
463 return requiredTrueValidator(control);
464 }
465 /**
466 * @description
467 * Validator that requires the control's value pass an email validation test.
468 *
469 * Tests the value using a [regular
470 * expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
471 * pattern suitable for common use cases. The pattern is based on the definition of a valid email
472 * address in the [WHATWG HTML
473 * specification](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address) with
474 * some enhancements to incorporate more RFC rules (such as rules related to domain names and the
475 * lengths of different parts of the address).
476 *
477 * The differences from the WHATWG version include:
478 * - Disallow `local-part` (the part before the `@` symbol) to begin or end with a period (`.`).
479 * - Disallow `local-part` to be longer than 64 characters.
480 * - Disallow the whole address to be longer than 254 characters.
481 *
482 * If this pattern does not satisfy your business needs, you can use `Validators.pattern()` to
483 * validate the value against a different pattern.
484 *
485 * @usageNotes
486 *
487 * ### Validate that the field matches a valid email pattern
488 *
489 * ```typescript
490 * const control = new FormControl('bad@', Validators.email);
491 *
492 * console.log(control.errors); // {email: true}
493 * ```
494 *
495 * @returns An error map with the `email` property
496 * if the validation check fails, otherwise `null`.
497 *
498 * @see {@link updateValueAndValidity()}
499 *
500 */
501 static email(control) {
502 return emailValidator(control);
503 }
504 /**
505 * @description
506 * Validator that requires the length of the control's value to be greater than or equal
507 * to the provided minimum length. This validator is also provided by default if you use the
508 * the HTML5 `minlength` attribute. Note that the `minLength` validator is intended to be used
509 * only for types that have a numeric `length` property, such as strings or arrays. The
510 * `minLength` validator logic is also not invoked for values when their `length` property is 0
511 * (for example in case of an empty string or an empty array), to support optional controls. You
512 * can use the standard `required` validator if empty values should not be considered valid.
513 *
514 * @usageNotes
515 *
516 * ### Validate that the field has a minimum of 3 characters
517 *
518 * ```typescript
519 * const control = new FormControl('ng', Validators.minLength(3));
520 *
521 * console.log(control.errors); // {minlength: {requiredLength: 3, actualLength: 2}}
522 * ```
523 *
524 * ```html
525 * <input minlength="5">
526 * ```
527 *
528 * @returns A validator function that returns an error map with the
529 * `minlength` property if the validation check fails, otherwise `null`.
530 *
531 * @see {@link updateValueAndValidity()}
532 *
533 */
534 static minLength(minLength) {
535 return minLengthValidator(minLength);
536 }
537 /**
538 * @description
539 * Validator that requires the length of the control's value to be less than or equal
540 * to the provided maximum length. This validator is also provided by default if you use the
541 * the HTML5 `maxlength` attribute. Note that the `maxLength` validator is intended to be used
542 * only for types that have a numeric `length` property, such as strings or arrays.
543 *
544 * @usageNotes
545 *
546 * ### Validate that the field has maximum of 5 characters
547 *
548 * ```typescript
549 * const control = new FormControl('Angular', Validators.maxLength(5));
550 *
551 * console.log(control.errors); // {maxlength: {requiredLength: 5, actualLength: 7}}
552 * ```
553 *
554 * ```html
555 * <input maxlength="5">
556 * ```
557 *
558 * @returns A validator function that returns an error map with the
559 * `maxlength` property if the validation check fails, otherwise `null`.
560 *
561 * @see {@link updateValueAndValidity()}
562 *
563 */
564 static maxLength(maxLength) {
565 return maxLengthValidator(maxLength);
566 }
567 /**
568 * @description
569 * Validator that requires the control's value to match a regex pattern. This validator is also
570 * provided by default if you use the HTML5 `pattern` attribute.
571 *
572 * @usageNotes
573 *
574 * ### Validate that the field only contains letters or spaces
575 *
576 * ```typescript
577 * const control = new FormControl('1', Validators.pattern('[a-zA-Z ]*'));
578 *
579 * console.log(control.errors); // {pattern: {requiredPattern: '^[a-zA-Z ]*$', actualValue: '1'}}
580 * ```
581 *
582 * ```html
583 * <input pattern="[a-zA-Z ]*">
584 * ```
585 *
586 * ### Pattern matching with the global or sticky flag
587 *
588 * `RegExp` objects created with the `g` or `y` flags that are passed into `Validators.pattern`
589 * can produce different results on the same input when validations are run consecutively. This is
590 * due to how the behavior of `RegExp.prototype.test` is
591 * specified in [ECMA-262](https://tc39.es/ecma262/#sec-regexpbuiltinexec)
592 * (`RegExp` preserves the index of the last match when the global or sticky flag is used).
593 * Due to this behavior, it is recommended that when using
594 * `Validators.pattern` you **do not** pass in a `RegExp` object with either the global or sticky
595 * flag enabled.
596 *
597 * ```typescript
598 * // Not recommended (since the `g` flag is used)
599 * const controlOne = new FormControl('1', Validators.pattern(/foo/g));
600 *
601 * // Good
602 * const controlTwo = new FormControl('1', Validators.pattern(/foo/));
603 * ```
604 *
605 * @param pattern A regular expression to be used as is to test the values, or a string.
606 * If a string is passed, the `^` character is prepended and the `$` character is
607 * appended to the provided string (if not already present), and the resulting regular
608 * expression is used to test the values.
609 *
610 * @returns A validator function that returns an error map with the
611 * `pattern` property if the validation check fails, otherwise `null`.
612 *
613 * @see {@link updateValueAndValidity()}
614 *
615 */
616 static pattern(pattern) {
617 return patternValidator(pattern);
618 }
619 /**
620 * @description
621 * Validator that performs no operation.
622 *
623 * @see {@link updateValueAndValidity()}
624 *
625 */
626 static nullValidator(control) {
627 return nullValidator(control);
628 }
629 static compose(validators) {
630 return compose(validators);
631 }
632 /**
633 * @description
634 * Compose multiple async validators into a single function that returns the union
635 * of the individual error objects for the provided control.
636 *
637 * @returns A validator function that returns an error map with the
638 * merged error objects of the async validators if the validation check fails, otherwise `null`.
639 *
640 * @see {@link updateValueAndValidity()}
641 *
642 */
643 static composeAsync(validators) {
644 return composeAsync(validators);
645 }
646}
647/**
648 * Validator that requires the control's value to be greater than or equal to the provided number.
649 * See `Validators.min` for additional information.
650 */
651function minValidator(min) {
652 return (control) => {
653 if (isEmptyInputValue(control.value) || isEmptyInputValue(min)) {
654 return null; // don't validate empty values to allow optional controls
655 }
656 const value = parseFloat(control.value);
657 // Controls with NaN values after parsing should be treated as not having a
658 // minimum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-min
659 return !isNaN(value) && value < min ? { 'min': { 'min': min, 'actual': control.value } } : null;
660 };
661}
662/**
663 * Validator that requires the control's value to be less than or equal to the provided number.
664 * See `Validators.max` for additional information.
665 */
666function maxValidator(max) {
667 return (control) => {
668 if (isEmptyInputValue(control.value) || isEmptyInputValue(max)) {
669 return null; // don't validate empty values to allow optional controls
670 }
671 const value = parseFloat(control.value);
672 // Controls with NaN values after parsing should be treated as not having a
673 // maximum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-max
674 return !isNaN(value) && value > max ? { 'max': { 'max': max, 'actual': control.value } } : null;
675 };
676}
677/**
678 * Validator that requires the control have a non-empty value.
679 * See `Validators.required` for additional information.
680 */
681function requiredValidator(control) {
682 return isEmptyInputValue(control.value) ? { 'required': true } : null;
683}
684/**
685 * Validator that requires the control's value be true. This validator is commonly
686 * used for required checkboxes.
687 * See `Validators.requiredTrue` for additional information.
688 */
689function requiredTrueValidator(control) {
690 return control.value === true ? null : { 'required': true };
691}
692/**
693 * Validator that requires the control's value pass an email validation test.
694 * See `Validators.email` for additional information.
695 */
696function emailValidator(control) {
697 if (isEmptyInputValue(control.value)) {
698 return null; // don't validate empty values to allow optional controls
699 }
700 return EMAIL_REGEXP.test(control.value) ? null : { 'email': true };
701}
702/**
703 * Validator that requires the length of the control's value to be greater than or equal
704 * to the provided minimum length. See `Validators.minLength` for additional information.
705 */
706function minLengthValidator(minLength) {
707 return (control) => {
708 if (isEmptyInputValue(control.value) || !hasValidLength(control.value)) {
709 // don't validate empty values to allow optional controls
710 // don't validate values without `length` property
711 return null;
712 }
713 return control.value.length < minLength ?
714 { 'minlength': { 'requiredLength': minLength, 'actualLength': control.value.length } } :
715 null;
716 };
717}
718/**
719 * Validator that requires the length of the control's value to be less than or equal
720 * to the provided maximum length. See `Validators.maxLength` for additional information.
721 */
722function maxLengthValidator(maxLength) {
723 return (control) => {
724 return hasValidLength(control.value) && control.value.length > maxLength ?
725 { 'maxlength': { 'requiredLength': maxLength, 'actualLength': control.value.length } } :
726 null;
727 };
728}
729/**
730 * Validator that requires the control's value to match a regex pattern.
731 * See `Validators.pattern` for additional information.
732 */
733function patternValidator(pattern) {
734 if (!pattern)
735 return nullValidator;
736 let regex;
737 let regexStr;
738 if (typeof pattern === 'string') {
739 regexStr = '';
740 if (pattern.charAt(0) !== '^')
741 regexStr += '^';
742 regexStr += pattern;
743 if (pattern.charAt(pattern.length - 1) !== '$')
744 regexStr += '$';
745 regex = new RegExp(regexStr);
746 }
747 else {
748 regexStr = pattern.toString();
749 regex = pattern;
750 }
751 return (control) => {
752 if (isEmptyInputValue(control.value)) {
753 return null; // don't validate empty values to allow optional controls
754 }
755 const value = control.value;
756 return regex.test(value) ? null :
757 { 'pattern': { 'requiredPattern': regexStr, 'actualValue': value } };
758 };
759}
760/**
761 * Function that has `ValidatorFn` shape, but performs no operation.
762 */
763function nullValidator(control) {
764 return null;
765}
766function isPresent(o) {
767 return o != null;
768}
769function toObservable(value) {
770 const obs = ɵisPromise(value) ? from(value) : value;
771 if ((typeof ngDevMode === 'undefined' || ngDevMode) && !(ɵisSubscribable(obs))) {
772 let errorMessage = `Expected async validator to return Promise or Observable.`;
773 // A synchronous validator will return object or null.
774 if (typeof value === 'object') {
775 errorMessage +=
776 ' Are you using a synchronous validator where an async validator is expected?';
777 }
778 throw new ɵRuntimeError(-1101 /* RuntimeErrorCode.WRONG_VALIDATOR_RETURN_TYPE */, errorMessage);
779 }
780 return obs;
781}
782function mergeErrors(arrayOfErrors) {
783 let res = {};
784 arrayOfErrors.forEach((errors) => {
785 res = errors != null ? { ...res, ...errors } : res;
786 });
787 return Object.keys(res).length === 0 ? null : res;
788}
789function executeValidators(control, validators) {
790 return validators.map(validator => validator(control));
791}
792function isValidatorFn(validator) {
793 return !validator.validate;
794}
795/**
796 * Given the list of validators that may contain both functions as well as classes, return the list
797 * of validator functions (convert validator classes into validator functions). This is needed to
798 * have consistent structure in validators list before composing them.
799 *
800 * @param validators The set of validators that may contain validators both in plain function form
801 * as well as represented as a validator class.
802 */
803function normalizeValidators(validators) {
804 return validators.map(validator => {
805 return isValidatorFn(validator) ?
806 validator :
807 ((c) => validator.validate(c));
808 });
809}
810/**
811 * Merges synchronous validators into a single validator function.
812 * See `Validators.compose` for additional information.
813 */
814function compose(validators) {
815 if (!validators)
816 return null;
817 const presentValidators = validators.filter(isPresent);
818 if (presentValidators.length == 0)
819 return null;
820 return function (control) {
821 return mergeErrors(executeValidators(control, presentValidators));
822 };
823}
824/**
825 * Accepts a list of validators of different possible shapes (`Validator` and `ValidatorFn`),
826 * normalizes the list (converts everything to `ValidatorFn`) and merges them into a single
827 * validator function.
828 */
829function composeValidators(validators) {
830 return validators != null ? compose(normalizeValidators(validators)) : null;
831}
832/**
833 * Merges asynchronous validators into a single validator function.
834 * See `Validators.composeAsync` for additional information.
835 */
836function composeAsync(validators) {
837 if (!validators)
838 return null;
839 const presentValidators = validators.filter(isPresent);
840 if (presentValidators.length == 0)
841 return null;
842 return function (control) {
843 const observables = executeValidators(control, presentValidators).map(toObservable);
844 return forkJoin(observables).pipe(map(mergeErrors));
845 };
846}
847/**
848 * Accepts a list of async validators of different possible shapes (`AsyncValidator` and
849 * `AsyncValidatorFn`), normalizes the list (converts everything to `AsyncValidatorFn`) and merges
850 * them into a single validator function.
851 */
852function composeAsyncValidators(validators) {
853 return validators != null ? composeAsync(normalizeValidators(validators)) :
854 null;
855}
856/**
857 * Merges raw control validators with a given directive validator and returns the combined list of
858 * validators as an array.
859 */
860function mergeValidators(controlValidators, dirValidator) {
861 if (controlValidators === null)
862 return [dirValidator];
863 return Array.isArray(controlValidators) ? [...controlValidators, dirValidator] :
864 [controlValidators, dirValidator];
865}
866/**
867 * Retrieves the list of raw synchronous validators attached to a given control.
868 */
869function getControlValidators(control) {
870 return control._rawValidators;
871}
872/**
873 * Retrieves the list of raw asynchronous validators attached to a given control.
874 */
875function getControlAsyncValidators(control) {
876 return control._rawAsyncValidators;
877}
878/**
879 * Accepts a singleton validator, an array, or null, and returns an array type with the provided
880 * validators.
881 *
882 * @param validators A validator, validators, or null.
883 * @returns A validators array.
884 */
885function makeValidatorsArray(validators) {
886 if (!validators)
887 return [];
888 return Array.isArray(validators) ? validators : [validators];
889}
890/**
891 * Determines whether a validator or validators array has a given validator.
892 *
893 * @param validators The validator or validators to compare against.
894 * @param validator The validator to check.
895 * @returns Whether the validator is present.
896 */
897function hasValidator(validators, validator) {
898 return Array.isArray(validators) ? validators.includes(validator) : validators === validator;
899}
900/**
901 * Combines two arrays of validators into one. If duplicates are provided, only one will be added.
902 *
903 * @param validators The new validators.
904 * @param currentValidators The base array of current validators.
905 * @returns An array of validators.
906 */
907function addValidators(validators, currentValidators) {
908 const current = makeValidatorsArray(currentValidators);
909 const validatorsToAdd = makeValidatorsArray(validators);
910 validatorsToAdd.forEach((v) => {
911 // Note: if there are duplicate entries in the new validators array,
912 // only the first one would be added to the current list of validators.
913 // Duplicate ones would be ignored since `hasValidator` would detect
914 // the presence of a validator function and we update the current list in place.
915 if (!hasValidator(current, v)) {
916 current.push(v);
917 }
918 });
919 return current;
920}
921function removeValidators(validators, currentValidators) {
922 return makeValidatorsArray(currentValidators).filter(v => !hasValidator(validators, v));
923}
924
925/**
926 * @description
927 * Base class for control directives.
928 *
929 * This class is only used internally in the `ReactiveFormsModule` and the `FormsModule`.
930 *
931 * @publicApi
932 */
933class AbstractControlDirective {
934 constructor() {
935 /**
936 * Set of synchronous validators as they were provided while calling `setValidators` function.
937 * @internal
938 */
939 this._rawValidators = [];
940 /**
941 * Set of asynchronous validators as they were provided while calling `setAsyncValidators`
942 * function.
943 * @internal
944 */
945 this._rawAsyncValidators = [];
946 /*
947 * The set of callbacks to be invoked when directive instance is being destroyed.
948 */
949 this._onDestroyCallbacks = [];
950 }
951 /**
952 * @description
953 * Reports the value of the control if it is present, otherwise null.
954 */
955 get value() {
956 return this.control ? this.control.value : null;
957 }
958 /**
959 * @description
960 * Reports whether the control is valid. A control is considered valid if no
961 * validation errors exist with the current value.
962 * If the control is not present, null is returned.
963 */
964 get valid() {
965 return this.control ? this.control.valid : null;
966 }
967 /**
968 * @description
969 * Reports whether the control is invalid, meaning that an error exists in the input value.
970 * If the control is not present, null is returned.
971 */
972 get invalid() {
973 return this.control ? this.control.invalid : null;
974 }
975 /**
976 * @description
977 * Reports whether a control is pending, meaning that async validation is occurring and
978 * errors are not yet available for the input value. If the control is not present, null is
979 * returned.
980 */
981 get pending() {
982 return this.control ? this.control.pending : null;
983 }
984 /**
985 * @description
986 * Reports whether the control is disabled, meaning that the control is disabled
987 * in the UI and is exempt from validation checks and excluded from aggregate
988 * values of ancestor controls. If the control is not present, null is returned.
989 */
990 get disabled() {
991 return this.control ? this.control.disabled : null;
992 }
993 /**
994 * @description
995 * Reports whether the control is enabled, meaning that the control is included in ancestor
996 * calculations of validity or value. If the control is not present, null is returned.
997 */
998 get enabled() {
999 return this.control ? this.control.enabled : null;
1000 }
1001 /**
1002 * @description
1003 * Reports the control's validation errors. If the control is not present, null is returned.
1004 */
1005 get errors() {
1006 return this.control ? this.control.errors : null;
1007 }
1008 /**
1009 * @description
1010 * Reports whether the control is pristine, meaning that the user has not yet changed
1011 * the value in the UI. If the control is not present, null is returned.
1012 */
1013 get pristine() {
1014 return this.control ? this.control.pristine : null;
1015 }
1016 /**
1017 * @description
1018 * Reports whether the control is dirty, meaning that the user has changed
1019 * the value in the UI. If the control is not present, null is returned.
1020 */
1021 get dirty() {
1022 return this.control ? this.control.dirty : null;
1023 }
1024 /**
1025 * @description
1026 * Reports whether the control is touched, meaning that the user has triggered
1027 * a `blur` event on it. If the control is not present, null is returned.
1028 */
1029 get touched() {
1030 return this.control ? this.control.touched : null;
1031 }
1032 /**
1033 * @description
1034 * Reports the validation status of the control. Possible values include:
1035 * 'VALID', 'INVALID', 'DISABLED', and 'PENDING'.
1036 * If the control is not present, null is returned.
1037 */
1038 get status() {
1039 return this.control ? this.control.status : null;
1040 }
1041 /**
1042 * @description
1043 * Reports whether the control is untouched, meaning that the user has not yet triggered
1044 * a `blur` event on it. If the control is not present, null is returned.
1045 */
1046 get untouched() {
1047 return this.control ? this.control.untouched : null;
1048 }
1049 /**
1050 * @description
1051 * Returns a multicasting observable that emits a validation status whenever it is
1052 * calculated for the control. If the control is not present, null is returned.
1053 */
1054 get statusChanges() {
1055 return this.control ? this.control.statusChanges : null;
1056 }
1057 /**
1058 * @description
1059 * Returns a multicasting observable of value changes for the control that emits every time the
1060 * value of the control changes in the UI or programmatically.
1061 * If the control is not present, null is returned.
1062 */
1063 get valueChanges() {
1064 return this.control ? this.control.valueChanges : null;
1065 }
1066 /**
1067 * @description
1068 * Returns an array that represents the path from the top-level form to this control.
1069 * Each index is the string name of the control on that level.
1070 */
1071 get path() {
1072 return null;
1073 }
1074 /**
1075 * Sets synchronous validators for this directive.
1076 * @internal
1077 */
1078 _setValidators(validators) {
1079 this._rawValidators = validators || [];
1080 this._composedValidatorFn = composeValidators(this._rawValidators);
1081 }
1082 /**
1083 * Sets asynchronous validators for this directive.
1084 * @internal
1085 */
1086 _setAsyncValidators(validators) {
1087 this._rawAsyncValidators = validators || [];
1088 this._composedAsyncValidatorFn = composeAsyncValidators(this._rawAsyncValidators);
1089 }
1090 /**
1091 * @description
1092 * Synchronous validator function composed of all the synchronous validators registered with this
1093 * directive.
1094 */
1095 get validator() {
1096 return this._composedValidatorFn || null;
1097 }
1098 /**
1099 * @description
1100 * Asynchronous validator function composed of all the asynchronous validators registered with
1101 * this directive.
1102 */
1103 get asyncValidator() {
1104 return this._composedAsyncValidatorFn || null;
1105 }
1106 /**
1107 * Internal function to register callbacks that should be invoked
1108 * when directive instance is being destroyed.
1109 * @internal
1110 */
1111 _registerOnDestroy(fn) {
1112 this._onDestroyCallbacks.push(fn);
1113 }
1114 /**
1115 * Internal function to invoke all registered "on destroy" callbacks.
1116 * Note: calling this function also clears the list of callbacks.
1117 * @internal
1118 */
1119 _invokeOnDestroyCallbacks() {
1120 this._onDestroyCallbacks.forEach(fn => fn());
1121 this._onDestroyCallbacks = [];
1122 }
1123 /**
1124 * @description
1125 * Resets the control with the provided value if the control is present.
1126 */
1127 reset(value = undefined) {
1128 if (this.control)
1129 this.control.reset(value);
1130 }
1131 /**
1132 * @description
1133 * Reports whether the control with the given path has the error specified.
1134 *
1135 * @param errorCode The code of the error to check
1136 * @param path A list of control names that designates how to move from the current control
1137 * to the control that should be queried for errors.
1138 *
1139 * @usageNotes
1140 * For example, for the following `FormGroup`:
1141 *
1142 * ```
1143 * form = new FormGroup({
1144 * address: new FormGroup({ street: new FormControl() })
1145 * });
1146 * ```
1147 *
1148 * The path to the 'street' control from the root form would be 'address' -> 'street'.
1149 *
1150 * It can be provided to this method in one of two formats:
1151 *
1152 * 1. An array of string control names, e.g. `['address', 'street']`
1153 * 1. A period-delimited list of control names in one string, e.g. `'address.street'`
1154 *
1155 * If no path is given, this method checks for the error on the current control.
1156 *
1157 * @returns whether the given error is present in the control at the given path.
1158 *
1159 * If the control is not present, false is returned.
1160 */
1161 hasError(errorCode, path) {
1162 return this.control ? this.control.hasError(errorCode, path) : false;
1163 }
1164 /**
1165 * @description
1166 * Reports error data for the control with the given path.
1167 *
1168 * @param errorCode The code of the error to check
1169 * @param path A list of control names that designates how to move from the current control
1170 * to the control that should be queried for errors.
1171 *
1172 * @usageNotes
1173 * For example, for the following `FormGroup`:
1174 *
1175 * ```
1176 * form = new FormGroup({
1177 * address: new FormGroup({ street: new FormControl() })
1178 * });
1179 * ```
1180 *
1181 * The path to the 'street' control from the root form would be 'address' -> 'street'.
1182 *
1183 * It can be provided to this method in one of two formats:
1184 *
1185 * 1. An array of string control names, e.g. `['address', 'street']`
1186 * 1. A period-delimited list of control names in one string, e.g. `'address.street'`
1187 *
1188 * @returns error data for that particular error. If the control or error is not present,
1189 * null is returned.
1190 */
1191 getError(errorCode, path) {
1192 return this.control ? this.control.getError(errorCode, path) : null;
1193 }
1194}
1195
1196/**
1197 * @description
1198 * A base class for directives that contain multiple registered instances of `NgControl`.
1199 * Only used by the forms module.
1200 *
1201 * @publicApi
1202 */
1203class ControlContainer extends AbstractControlDirective {
1204 /**
1205 * @description
1206 * The top-level form directive for the control.
1207 */
1208 get formDirective() {
1209 return null;
1210 }
1211 /**
1212 * @description
1213 * The path to this group.
1214 */
1215 get path() {
1216 return null;
1217 }
1218}
1219
1220/**
1221 * @description
1222 * A base class that all `FormControl`-based directives extend. It binds a `FormControl`
1223 * object to a DOM element.
1224 *
1225 * @publicApi
1226 */
1227class NgControl extends AbstractControlDirective {
1228 constructor() {
1229 super(...arguments);
1230 /**
1231 * @description
1232 * The parent form for the control.
1233 *
1234 * @internal
1235 */
1236 this._parent = null;
1237 /**
1238 * @description
1239 * The name for the control
1240 */
1241 this.name = null;
1242 /**
1243 * @description
1244 * The value accessor for the control
1245 */
1246 this.valueAccessor = null;
1247 }
1248}
1249
1250// DO NOT REFACTOR!
1251// Each status is represented by a separate function to make sure that
1252// advanced Closure Compiler optimizations related to property renaming
1253// can work correctly.
1254class AbstractControlStatus {
1255 constructor(cd) {
1256 this._cd = cd;
1257 }
1258 get isTouched() {
1259 return !!this._cd?.control?.touched;
1260 }
1261 get isUntouched() {
1262 return !!this._cd?.control?.untouched;
1263 }
1264 get isPristine() {
1265 return !!this._cd?.control?.pristine;
1266 }
1267 get isDirty() {
1268 return !!this._cd?.control?.dirty;
1269 }
1270 get isValid() {
1271 return !!this._cd?.control?.valid;
1272 }
1273 get isInvalid() {
1274 return !!this._cd?.control?.invalid;
1275 }
1276 get isPending() {
1277 return !!this._cd?.control?.pending;
1278 }
1279 get isSubmitted() {
1280 // We check for the `submitted` field from `NgForm` and `FormGroupDirective` classes, but
1281 // we avoid instanceof checks to prevent non-tree-shakable references to those types.
1282 return !!this._cd?.submitted;
1283 }
1284}
1285const ngControlStatusHost = {
1286 '[class.ng-untouched]': 'isUntouched',
1287 '[class.ng-touched]': 'isTouched',
1288 '[class.ng-pristine]': 'isPristine',
1289 '[class.ng-dirty]': 'isDirty',
1290 '[class.ng-valid]': 'isValid',
1291 '[class.ng-invalid]': 'isInvalid',
1292 '[class.ng-pending]': 'isPending',
1293};
1294const ngGroupStatusHost = {
1295 ...ngControlStatusHost,
1296 '[class.ng-submitted]': 'isSubmitted',
1297};
1298/**
1299 * @description
1300 * Directive automatically applied to Angular form controls that sets CSS classes
1301 * based on control status.
1302 *
1303 * @usageNotes
1304 *
1305 * ### CSS classes applied
1306 *
1307 * The following classes are applied as the properties become true:
1308 *
1309 * * ng-valid
1310 * * ng-invalid
1311 * * ng-pending
1312 * * ng-pristine
1313 * * ng-dirty
1314 * * ng-untouched
1315 * * ng-touched
1316 *
1317 * @ngModule ReactiveFormsModule
1318 * @ngModule FormsModule
1319 * @publicApi
1320 */
1321class NgControlStatus extends AbstractControlStatus {
1322 constructor(cd) {
1323 super(cd);
1324 }
1325 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NgControlStatus, deps: [{ token: NgControl, self: true }], target: i0.ɵɵFactoryTarget.Directive }); }
1326 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: NgControlStatus, selector: "[formControlName],[ngModel],[formControl]", host: { properties: { "class.ng-untouched": "isUntouched", "class.ng-touched": "isTouched", "class.ng-pristine": "isPristine", "class.ng-dirty": "isDirty", "class.ng-valid": "isValid", "class.ng-invalid": "isInvalid", "class.ng-pending": "isPending" } }, usesInheritance: true, ngImport: i0 }); }
1327}
1328i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NgControlStatus, decorators: [{
1329 type: Directive,
1330 args: [{ selector: '[formControlName],[ngModel],[formControl]', host: ngControlStatusHost }]
1331 }], ctorParameters: () => [{ type: NgControl, decorators: [{
1332 type: Self
1333 }] }] });
1334/**
1335 * @description
1336 * Directive automatically applied to Angular form groups that sets CSS classes
1337 * based on control status (valid/invalid/dirty/etc). On groups, this includes the additional
1338 * class ng-submitted.
1339 *
1340 * @see {@link NgControlStatus}
1341 *
1342 * @ngModule ReactiveFormsModule
1343 * @ngModule FormsModule
1344 * @publicApi
1345 */
1346class NgControlStatusGroup extends AbstractControlStatus {
1347 constructor(cd) {
1348 super(cd);
1349 }
1350 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NgControlStatusGroup, deps: [{ token: ControlContainer, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive }); }
1351 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]", host: { properties: { "class.ng-untouched": "isUntouched", "class.ng-touched": "isTouched", "class.ng-pristine": "isPristine", "class.ng-dirty": "isDirty", "class.ng-valid": "isValid", "class.ng-invalid": "isInvalid", "class.ng-pending": "isPending", "class.ng-submitted": "isSubmitted" } }, usesInheritance: true, ngImport: i0 }); }
1352}
1353i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NgControlStatusGroup, decorators: [{
1354 type: Directive,
1355 args: [{
1356 selector: '[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]',
1357 host: ngGroupStatusHost
1358 }]
1359 }], ctorParameters: () => [{ type: ControlContainer, decorators: [{
1360 type: Optional
1361 }, {
1362 type: Self
1363 }] }] });
1364
1365const formControlNameExample = `
1366 <div [formGroup]="myGroup">
1367 <input formControlName="firstName">
1368 </div>
1369
1370 In your class:
1371
1372 this.myGroup = new FormGroup({
1373 firstName: new FormControl()
1374 });`;
1375const formGroupNameExample = `
1376 <div [formGroup]="myGroup">
1377 <div formGroupName="person">
1378 <input formControlName="firstName">
1379 </div>
1380 </div>
1381
1382 In your class:
1383
1384 this.myGroup = new FormGroup({
1385 person: new FormGroup({ firstName: new FormControl() })
1386 });`;
1387const formArrayNameExample = `
1388 <div [formGroup]="myGroup">
1389 <div formArrayName="cities">
1390 <div *ngFor="let city of cityArray.controls; index as i">
1391 <input [formControlName]="i">
1392 </div>
1393 </div>
1394 </div>
1395
1396 In your class:
1397
1398 this.cityArray = new FormArray([new FormControl('SF')]);
1399 this.myGroup = new FormGroup({
1400 cities: this.cityArray
1401 });`;
1402const ngModelGroupExample = `
1403 <form>
1404 <div ngModelGroup="person">
1405 <input [(ngModel)]="person.name" name="firstName">
1406 </div>
1407 </form>`;
1408const ngModelWithFormGroupExample = `
1409 <div [formGroup]="myGroup">
1410 <input formControlName="firstName">
1411 <input [(ngModel)]="showMoreControls" [ngModelOptions]="{standalone: true}">
1412 </div>
1413`;
1414
1415function controlParentException() {
1416 return new ɵRuntimeError(1050 /* RuntimeErrorCode.FORM_CONTROL_NAME_MISSING_PARENT */, `formControlName must be used with a parent formGroup directive. You'll want to add a formGroup
1417 directive and pass it an existing FormGroup instance (you can create one in your class).
1418
1419 Example:
1420
1421 ${formControlNameExample}`);
1422}
1423function ngModelGroupException() {
1424 return new ɵRuntimeError(1051 /* RuntimeErrorCode.FORM_CONTROL_NAME_INSIDE_MODEL_GROUP */, `formControlName cannot be used with an ngModelGroup parent. It is only compatible with parents
1425 that also have a "form" prefix: formGroupName, formArrayName, or formGroup.
1426
1427 Option 1: Update the parent to be formGroupName (reactive form strategy)
1428
1429 ${formGroupNameExample}
1430
1431 Option 2: Use ngModel instead of formControlName (template-driven strategy)
1432
1433 ${ngModelGroupExample}`);
1434}
1435function missingFormException() {
1436 return new ɵRuntimeError(1052 /* RuntimeErrorCode.FORM_GROUP_MISSING_INSTANCE */, `formGroup expects a FormGroup instance. Please pass one in.
1437
1438 Example:
1439
1440 ${formControlNameExample}`);
1441}
1442function groupParentException() {
1443 return new ɵRuntimeError(1053 /* RuntimeErrorCode.FORM_GROUP_NAME_MISSING_PARENT */, `formGroupName must be used with a parent formGroup directive. You'll want to add a formGroup
1444 directive and pass it an existing FormGroup instance (you can create one in your class).
1445
1446 Example:
1447
1448 ${formGroupNameExample}`);
1449}
1450function arrayParentException() {
1451 return new ɵRuntimeError(1054 /* RuntimeErrorCode.FORM_ARRAY_NAME_MISSING_PARENT */, `formArrayName must be used with a parent formGroup directive. You'll want to add a formGroup
1452 directive and pass it an existing FormGroup instance (you can create one in your class).
1453
1454 Example:
1455
1456 ${formArrayNameExample}`);
1457}
1458const disabledAttrWarning = `
1459 It looks like you're using the disabled attribute with a reactive form directive. If you set disabled to true
1460 when you set up this control in your component class, the disabled attribute will actually be set in the DOM for
1461 you. We recommend using this approach to avoid 'changed after checked' errors.
1462
1463 Example:
1464 // Specify the \`disabled\` property at control creation time:
1465 form = new FormGroup({
1466 first: new FormControl({value: 'Nancy', disabled: true}, Validators.required),
1467 last: new FormControl('Drew', Validators.required)
1468 });
1469
1470 // Controls can also be enabled/disabled after creation:
1471 form.get('first')?.enable();
1472 form.get('last')?.disable();
1473`;
1474const asyncValidatorsDroppedWithOptsWarning = `
1475 It looks like you're constructing using a FormControl with both an options argument and an
1476 async validators argument. Mixing these arguments will cause your async validators to be dropped.
1477 You should either put all your validators in the options object, or in separate validators
1478 arguments. For example:
1479
1480 // Using validators arguments
1481 fc = new FormControl(42, Validators.required, myAsyncValidator);
1482
1483 // Using AbstractControlOptions
1484 fc = new FormControl(42, {validators: Validators.required, asyncValidators: myAV});
1485
1486 // Do NOT mix them: async validators will be dropped!
1487 fc = new FormControl(42, {validators: Validators.required}, /* Oops! */ myAsyncValidator);
1488`;
1489function ngModelWarning(directiveName) {
1490 return `
1491 It looks like you're using ngModel on the same form field as ${directiveName}.
1492 Support for using the ngModel input property and ngModelChange event with
1493 reactive form directives has been deprecated in Angular v6 and will be removed
1494 in a future version of Angular.
1495
1496 For more information on this, see our API docs here:
1497 https://angular.io/api/forms/${directiveName === 'formControl' ? 'FormControlDirective' : 'FormControlName'}#use-with-ngmodel
1498 `;
1499}
1500function describeKey(isFormGroup, key) {
1501 return isFormGroup ? `with name: '${key}'` : `at index: ${key}`;
1502}
1503function noControlsError(isFormGroup) {
1504 return `
1505 There are no form controls registered with this ${isFormGroup ? 'group' : 'array'} yet. If you're using ngModel,
1506 you may want to check next tick (e.g. use setTimeout).
1507 `;
1508}
1509function missingControlError(isFormGroup, key) {
1510 return `Cannot find form control ${describeKey(isFormGroup, key)}`;
1511}
1512function missingControlValueError(isFormGroup, key) {
1513 return `Must supply a value for form control ${describeKey(isFormGroup, key)}`;
1514}
1515
1516/**
1517 * Reports that a control is valid, meaning that no errors exist in the input value.
1518 *
1519 * @see {@link status}
1520 */
1521const VALID = 'VALID';
1522/**
1523 * Reports that a control is invalid, meaning that an error exists in the input value.
1524 *
1525 * @see {@link status}
1526 */
1527const INVALID = 'INVALID';
1528/**
1529 * Reports that a control is pending, meaning that async validation is occurring and
1530 * errors are not yet available for the input value.
1531 *
1532 * @see {@link markAsPending}
1533 * @see {@link status}
1534 */
1535const PENDING = 'PENDING';
1536/**
1537 * Reports that a control is disabled, meaning that the control is exempt from ancestor
1538 * calculations of validity or value.
1539 *
1540 * @see {@link markAsDisabled}
1541 * @see {@link status}
1542 */
1543const DISABLED = 'DISABLED';
1544/**
1545 * Gets validators from either an options object or given validators.
1546 */
1547function pickValidators(validatorOrOpts) {
1548 return (isOptionsObj(validatorOrOpts) ? validatorOrOpts.validators : validatorOrOpts) || null;
1549}
1550/**
1551 * Creates validator function by combining provided validators.
1552 */
1553function coerceToValidator(validator) {
1554 return Array.isArray(validator) ? composeValidators(validator) : validator || null;
1555}
1556/**
1557 * Gets async validators from either an options object or given validators.
1558 */
1559function pickAsyncValidators(asyncValidator, validatorOrOpts) {
1560 if (typeof ngDevMode === 'undefined' || ngDevMode) {
1561 if (isOptionsObj(validatorOrOpts) && asyncValidator) {
1562 console.warn(asyncValidatorsDroppedWithOptsWarning);
1563 }
1564 }
1565 return (isOptionsObj(validatorOrOpts) ? validatorOrOpts.asyncValidators : asyncValidator) || null;
1566}
1567/**
1568 * Creates async validator function by combining provided async validators.
1569 */
1570function coerceToAsyncValidator(asyncValidator) {
1571 return Array.isArray(asyncValidator) ? composeAsyncValidators(asyncValidator) :
1572 asyncValidator || null;
1573}
1574function isOptionsObj(validatorOrOpts) {
1575 return validatorOrOpts != null && !Array.isArray(validatorOrOpts) &&
1576 typeof validatorOrOpts === 'object';
1577}
1578function assertControlPresent(parent, isGroup, key) {
1579 const controls = parent.controls;
1580 const collection = isGroup ? Object.keys(controls) : controls;
1581 if (!collection.length) {
1582 throw new ɵRuntimeError(1000 /* RuntimeErrorCode.NO_CONTROLS */, (typeof ngDevMode === 'undefined' || ngDevMode) ? noControlsError(isGroup) : '');
1583 }
1584 if (!controls[key]) {
1585 throw new ɵRuntimeError(1001 /* RuntimeErrorCode.MISSING_CONTROL */, (typeof ngDevMode === 'undefined' || ngDevMode) ? missingControlError(isGroup, key) : '');
1586 }
1587}
1588function assertAllValuesPresent(control, isGroup, value) {
1589 control._forEachChild((_, key) => {
1590 if (value[key] === undefined) {
1591 throw new ɵRuntimeError(1002 /* RuntimeErrorCode.MISSING_CONTROL_VALUE */, (typeof ngDevMode === 'undefined' || ngDevMode) ? missingControlValueError(isGroup, key) :
1592 '');
1593 }
1594 });
1595}
1596// clang-format on
1597/**
1598 * This is the base class for `FormControl`, `FormGroup`, and `FormArray`.
1599 *
1600 * It provides some of the shared behavior that all controls and groups of controls have, like
1601 * running validators, calculating status, and resetting state. It also defines the properties
1602 * that are shared between all sub-classes, like `value`, `valid`, and `dirty`. It shouldn't be
1603 * instantiated directly.
1604 *
1605 * The first type parameter TValue represents the value type of the control (`control.value`).
1606 * The optional type parameter TRawValue represents the raw value type (`control.getRawValue()`).
1607 *
1608 * @see [Forms Guide](/guide/forms)
1609 * @see [Reactive Forms Guide](/guide/reactive-forms)
1610 * @see [Dynamic Forms Guide](/guide/dynamic-form)
1611 *
1612 * @publicApi
1613 */
1614class AbstractControl {
1615 /**
1616 * Initialize the AbstractControl instance.
1617 *
1618 * @param validators The function or array of functions that is used to determine the validity of
1619 * this control synchronously.
1620 * @param asyncValidators The function or array of functions that is used to determine validity of
1621 * this control asynchronously.
1622 */
1623 constructor(validators, asyncValidators) {
1624 /** @internal */
1625 this._pendingDirty = false;
1626 /**
1627 * Indicates that a control has its own pending asynchronous validation in progress.
1628 *
1629 * @internal
1630 */
1631 this._hasOwnPendingAsyncValidator = false;
1632 /** @internal */
1633 this._pendingTouched = false;
1634 /** @internal */
1635 this._onCollectionChange = () => { };
1636 this._parent = null;
1637 /**
1638 * A control is `pristine` if the user has not yet changed
1639 * the value in the UI.
1640 *
1641 * @returns True if the user has not yet changed the value in the UI; compare `dirty`.
1642 * Programmatic changes to a control's value do not mark it dirty.
1643 */
1644 this.pristine = true;
1645 /**
1646 * True if the control is marked as `touched`.
1647 *
1648 * A control is marked `touched` once the user has triggered
1649 * a `blur` event on it.
1650 */
1651 this.touched = false;
1652 /** @internal */
1653 this._onDisabledChange = [];
1654 this._assignValidators(validators);
1655 this._assignAsyncValidators(asyncValidators);
1656 }
1657 /**
1658 * Returns the function that is used to determine the validity of this control synchronously.
1659 * If multiple validators have been added, this will be a single composed function.
1660 * See `Validators.compose()` for additional information.
1661 */
1662 get validator() {
1663 return this._composedValidatorFn;
1664 }
1665 set validator(validatorFn) {
1666 this._rawValidators = this._composedValidatorFn = validatorFn;
1667 }
1668 /**
1669 * Returns the function that is used to determine the validity of this control asynchronously.
1670 * If multiple validators have been added, this will be a single composed function.
1671 * See `Validators.compose()` for additional information.
1672 */
1673 get asyncValidator() {
1674 return this._composedAsyncValidatorFn;
1675 }
1676 set asyncValidator(asyncValidatorFn) {
1677 this._rawAsyncValidators = this._composedAsyncValidatorFn = asyncValidatorFn;
1678 }
1679 /**
1680 * The parent control.
1681 */
1682 get parent() {
1683 return this._parent;
1684 }
1685 /**
1686 * A control is `valid` when its `status` is `VALID`.
1687 *
1688 * @see {@link AbstractControl.status}
1689 *
1690 * @returns True if the control has passed all of its validation tests,
1691 * false otherwise.
1692 */
1693 get valid() {
1694 return this.status === VALID;
1695 }
1696 /**
1697 * A control is `invalid` when its `status` is `INVALID`.
1698 *
1699 * @see {@link AbstractControl.status}
1700 *
1701 * @returns True if this control has failed one or more of its validation checks,
1702 * false otherwise.
1703 */
1704 get invalid() {
1705 return this.status === INVALID;
1706 }
1707 /**
1708 * A control is `pending` when its `status` is `PENDING`.
1709 *
1710 * @see {@link AbstractControl.status}
1711 *
1712 * @returns True if this control is in the process of conducting a validation check,
1713 * false otherwise.
1714 */
1715 get pending() {
1716 return this.status == PENDING;
1717 }
1718 /**
1719 * A control is `disabled` when its `status` is `DISABLED`.
1720 *
1721 * Disabled controls are exempt from validation checks and
1722 * are not included in the aggregate value of their ancestor
1723 * controls.
1724 *
1725 * @see {@link AbstractControl.status}
1726 *
1727 * @returns True if the control is disabled, false otherwise.
1728 */
1729 get disabled() {
1730 return this.status === DISABLED;
1731 }
1732 /**
1733 * A control is `enabled` as long as its `status` is not `DISABLED`.
1734 *
1735 * @returns True if the control has any status other than 'DISABLED',
1736 * false if the status is 'DISABLED'.
1737 *
1738 * @see {@link AbstractControl.status}
1739 *
1740 */
1741 get enabled() {
1742 return this.status !== DISABLED;
1743 }
1744 /**
1745 * A control is `dirty` if the user has changed the value
1746 * in the UI.
1747 *
1748 * @returns True if the user has changed the value of this control in the UI; compare `pristine`.
1749 * Programmatic changes to a control's value do not mark it dirty.
1750 */
1751 get dirty() {
1752 return !this.pristine;
1753 }
1754 /**
1755 * True if the control has not been marked as touched
1756 *
1757 * A control is `untouched` if the user has not yet triggered
1758 * a `blur` event on it.
1759 */
1760 get untouched() {
1761 return !this.touched;
1762 }
1763 /**
1764 * Reports the update strategy of the `AbstractControl` (meaning
1765 * the event on which the control updates itself).
1766 * Possible values: `'change'` | `'blur'` | `'submit'`
1767 * Default value: `'change'`
1768 */
1769 get updateOn() {
1770 return this._updateOn ? this._updateOn : (this.parent ? this.parent.updateOn : 'change');
1771 }
1772 /**
1773 * Sets the synchronous validators that are active on this control. Calling
1774 * this overwrites any existing synchronous validators.
1775 *
1776 * When you add or remove a validator at run time, you must call
1777 * `updateValueAndValidity()` for the new validation to take effect.
1778 *
1779 * If you want to add a new validator without affecting existing ones, consider
1780 * using `addValidators()` method instead.
1781 */
1782 setValidators(validators) {
1783 this._assignValidators(validators);
1784 }
1785 /**
1786 * Sets the asynchronous validators that are active on this control. Calling this
1787 * overwrites any existing asynchronous validators.
1788 *
1789 * When you add or remove a validator at run time, you must call
1790 * `updateValueAndValidity()` for the new validation to take effect.
1791 *
1792 * If you want to add a new validator without affecting existing ones, consider
1793 * using `addAsyncValidators()` method instead.
1794 */
1795 setAsyncValidators(validators) {
1796 this._assignAsyncValidators(validators);
1797 }
1798 /**
1799 * Add a synchronous validator or validators to this control, without affecting other validators.
1800 *
1801 * When you add or remove a validator at run time, you must call
1802 * `updateValueAndValidity()` for the new validation to take effect.
1803 *
1804 * Adding a validator that already exists will have no effect. If duplicate validator functions
1805 * are present in the `validators` array, only the first instance would be added to a form
1806 * control.
1807 *
1808 * @param validators The new validator function or functions to add to this control.
1809 */
1810 addValidators(validators) {
1811 this.setValidators(addValidators(validators, this._rawValidators));
1812 }
1813 /**
1814 * Add an asynchronous validator or validators to this control, without affecting other
1815 * validators.
1816 *
1817 * When you add or remove a validator at run time, you must call
1818 * `updateValueAndValidity()` for the new validation to take effect.
1819 *
1820 * Adding a validator that already exists will have no effect.
1821 *
1822 * @param validators The new asynchronous validator function or functions to add to this control.
1823 */
1824 addAsyncValidators(validators) {
1825 this.setAsyncValidators(addValidators(validators, this._rawAsyncValidators));
1826 }
1827 /**
1828 * Remove a synchronous validator from this control, without affecting other validators.
1829 * Validators are compared by function reference; you must pass a reference to the exact same
1830 * validator function as the one that was originally set. If a provided validator is not found,
1831 * it is ignored.
1832 *
1833 * @usageNotes
1834 *
1835 * ### Reference to a ValidatorFn
1836 *
1837 * ```
1838 * // Reference to the RequiredValidator
1839 * const ctrl = new FormControl<string | null>('', Validators.required);
1840 * ctrl.removeValidators(Validators.required);
1841 *
1842 * // Reference to anonymous function inside MinValidator
1843 * const minValidator = Validators.min(3);
1844 * const ctrl = new FormControl<string | null>('', minValidator);
1845 * expect(ctrl.hasValidator(minValidator)).toEqual(true)
1846 * expect(ctrl.hasValidator(Validators.min(3))).toEqual(false)
1847 *
1848 * ctrl.removeValidators(minValidator);
1849 * ```
1850 *
1851 * When you add or remove a validator at run time, you must call
1852 * `updateValueAndValidity()` for the new validation to take effect.
1853 *
1854 * @param validators The validator or validators to remove.
1855 */
1856 removeValidators(validators) {
1857 this.setValidators(removeValidators(validators, this._rawValidators));
1858 }
1859 /**
1860 * Remove an asynchronous validator from this control, without affecting other validators.
1861 * Validators are compared by function reference; you must pass a reference to the exact same
1862 * validator function as the one that was originally set. If a provided validator is not found, it
1863 * is ignored.
1864 *
1865 * When you add or remove a validator at run time, you must call
1866 * `updateValueAndValidity()` for the new validation to take effect.
1867 *
1868 * @param validators The asynchronous validator or validators to remove.
1869 */
1870 removeAsyncValidators(validators) {
1871 this.setAsyncValidators(removeValidators(validators, this._rawAsyncValidators));
1872 }
1873 /**
1874 * Check whether a synchronous validator function is present on this control. The provided
1875 * validator must be a reference to the exact same function that was provided.
1876 *
1877 * @usageNotes
1878 *
1879 * ### Reference to a ValidatorFn
1880 *
1881 * ```
1882 * // Reference to the RequiredValidator
1883 * const ctrl = new FormControl<number | null>(0, Validators.required);
1884 * expect(ctrl.hasValidator(Validators.required)).toEqual(true)
1885 *
1886 * // Reference to anonymous function inside MinValidator
1887 * const minValidator = Validators.min(3);
1888 * const ctrl = new FormControl<number | null>(0, minValidator);
1889 * expect(ctrl.hasValidator(minValidator)).toEqual(true)
1890 * expect(ctrl.hasValidator(Validators.min(3))).toEqual(false)
1891 * ```
1892 *
1893 * @param validator The validator to check for presence. Compared by function reference.
1894 * @returns Whether the provided validator was found on this control.
1895 */
1896 hasValidator(validator) {
1897 return hasValidator(this._rawValidators, validator);
1898 }
1899 /**
1900 * Check whether an asynchronous validator function is present on this control. The provided
1901 * validator must be a reference to the exact same function that was provided.
1902 *
1903 * @param validator The asynchronous validator to check for presence. Compared by function
1904 * reference.
1905 * @returns Whether the provided asynchronous validator was found on this control.
1906 */
1907 hasAsyncValidator(validator) {
1908 return hasValidator(this._rawAsyncValidators, validator);
1909 }
1910 /**
1911 * Empties out the synchronous validator list.
1912 *
1913 * When you add or remove a validator at run time, you must call
1914 * `updateValueAndValidity()` for the new validation to take effect.
1915 *
1916 */
1917 clearValidators() {
1918 this.validator = null;
1919 }
1920 /**
1921 * Empties out the async validator list.
1922 *
1923 * When you add or remove a validator at run time, you must call
1924 * `updateValueAndValidity()` for the new validation to take effect.
1925 *
1926 */
1927 clearAsyncValidators() {
1928 this.asyncValidator = null;
1929 }
1930 /**
1931 * Marks the control as `touched`. A control is touched by focus and
1932 * blur events that do not change the value.
1933 *
1934 * @see {@link markAsUntouched()}
1935 * @see {@link markAsDirty()}
1936 * @see {@link markAsPristine()}
1937 *
1938 * @param opts Configuration options that determine how the control propagates changes
1939 * and emits events after marking is applied.
1940 * * `onlySelf`: When true, mark only this control. When false or not supplied,
1941 * marks all direct ancestors. Default is false.
1942 */
1943 markAsTouched(opts = {}) {
1944 this.touched = true;
1945 if (this._parent && !opts.onlySelf) {
1946 this._parent.markAsTouched(opts);
1947 }
1948 }
1949 /**
1950 * Marks the control and all its descendant controls as `touched`.
1951 * @see {@link markAsTouched()}
1952 */
1953 markAllAsTouched() {
1954 this.markAsTouched({ onlySelf: true });
1955 this._forEachChild((control) => control.markAllAsTouched());
1956 }
1957 /**
1958 * Marks the control as `untouched`.
1959 *
1960 * If the control has any children, also marks all children as `untouched`
1961 * and recalculates the `touched` status of all parent controls.
1962 *
1963 * @see {@link markAsTouched()}
1964 * @see {@link markAsDirty()}
1965 * @see {@link markAsPristine()}
1966 *
1967 * @param opts Configuration options that determine how the control propagates changes
1968 * and emits events after the marking is applied.
1969 * * `onlySelf`: When true, mark only this control. When false or not supplied,
1970 * marks all direct ancestors. Default is false.
1971 */
1972 markAsUntouched(opts = {}) {
1973 this.touched = false;
1974 this._pendingTouched = false;
1975 this._forEachChild((control) => {
1976 control.markAsUntouched({ onlySelf: true });
1977 });
1978 if (this._parent && !opts.onlySelf) {
1979 this._parent._updateTouched(opts);
1980 }
1981 }
1982 /**
1983 * Marks the control as `dirty`. A control becomes dirty when
1984 * the control's value is changed through the UI; compare `markAsTouched`.
1985 *
1986 * @see {@link markAsTouched()}
1987 * @see {@link markAsUntouched()}
1988 * @see {@link markAsPristine()}
1989 *
1990 * @param opts Configuration options that determine how the control propagates changes
1991 * and emits events after marking is applied.
1992 * * `onlySelf`: When true, mark only this control. When false or not supplied,
1993 * marks all direct ancestors. Default is false.
1994 */
1995 markAsDirty(opts = {}) {
1996 this.pristine = false;
1997 if (this._parent && !opts.onlySelf) {
1998 this._parent.markAsDirty(opts);
1999 }
2000 }
2001 /**
2002 * Marks the control as `pristine`.
2003 *
2004 * If the control has any children, marks all children as `pristine`,
2005 * and recalculates the `pristine` status of all parent
2006 * controls.
2007 *
2008 * @see {@link markAsTouched()}
2009 * @see {@link markAsUntouched()}
2010 * @see {@link markAsDirty()}
2011 *
2012 * @param opts Configuration options that determine how the control emits events after
2013 * marking is applied.
2014 * * `onlySelf`: When true, mark only this control. When false or not supplied,
2015 * marks all direct ancestors. Default is false.
2016 */
2017 markAsPristine(opts = {}) {
2018 this.pristine = true;
2019 this._pendingDirty = false;
2020 this._forEachChild((control) => {
2021 control.markAsPristine({ onlySelf: true });
2022 });
2023 if (this._parent && !opts.onlySelf) {
2024 this._parent._updatePristine(opts);
2025 }
2026 }
2027 /**
2028 * Marks the control as `pending`.
2029 *
2030 * A control is pending while the control performs async validation.
2031 *
2032 * @see {@link AbstractControl.status}
2033 *
2034 * @param opts Configuration options that determine how the control propagates changes and
2035 * emits events after marking is applied.
2036 * * `onlySelf`: When true, mark only this control. When false or not supplied,
2037 * marks all direct ancestors. Default is false.
2038 * * `emitEvent`: When true or not supplied (the default), the `statusChanges`
2039 * observable emits an event with the latest status the control is marked pending.
2040 * When false, no events are emitted.
2041 *
2042 */
2043 markAsPending(opts = {}) {
2044 this.status = PENDING;
2045 if (opts.emitEvent !== false) {
2046 this.statusChanges.emit(this.status);
2047 }
2048 if (this._parent && !opts.onlySelf) {
2049 this._parent.markAsPending(opts);
2050 }
2051 }
2052 /**
2053 * Disables the control. This means the control is exempt from validation checks and
2054 * excluded from the aggregate value of any parent. Its status is `DISABLED`.
2055 *
2056 * If the control has children, all children are also disabled.
2057 *
2058 * @see {@link AbstractControl.status}
2059 *
2060 * @param opts Configuration options that determine how the control propagates
2061 * changes and emits events after the control is disabled.
2062 * * `onlySelf`: When true, mark only this control. When false or not supplied,
2063 * marks all direct ancestors. Default is false.
2064 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
2065 * `valueChanges`
2066 * observables emit events with the latest status and value when the control is disabled.
2067 * When false, no events are emitted.
2068 */
2069 disable(opts = {}) {
2070 // If parent has been marked artificially dirty we don't want to re-calculate the
2071 // parent's dirtiness based on the children.
2072 const skipPristineCheck = this._parentMarkedDirty(opts.onlySelf);
2073 this.status = DISABLED;
2074 this.errors = null;
2075 this._forEachChild((control) => {
2076 control.disable({ ...opts, onlySelf: true });
2077 });
2078 this._updateValue();
2079 if (opts.emitEvent !== false) {
2080 this.valueChanges.emit(this.value);
2081 this.statusChanges.emit(this.status);
2082 }
2083 this._updateAncestors({ ...opts, skipPristineCheck });
2084 this._onDisabledChange.forEach((changeFn) => changeFn(true));
2085 }
2086 /**
2087 * Enables the control. This means the control is included in validation checks and
2088 * the aggregate value of its parent. Its status recalculates based on its value and
2089 * its validators.
2090 *
2091 * By default, if the control has children, all children are enabled.
2092 *
2093 * @see {@link AbstractControl.status}
2094 *
2095 * @param opts Configure options that control how the control propagates changes and
2096 * emits events when marked as untouched
2097 * * `onlySelf`: When true, mark only this control. When false or not supplied,
2098 * marks all direct ancestors. Default is false.
2099 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
2100 * `valueChanges`
2101 * observables emit events with the latest status and value when the control is enabled.
2102 * When false, no events are emitted.
2103 */
2104 enable(opts = {}) {
2105 // If parent has been marked artificially dirty we don't want to re-calculate the
2106 // parent's dirtiness based on the children.
2107 const skipPristineCheck = this._parentMarkedDirty(opts.onlySelf);
2108 this.status = VALID;
2109 this._forEachChild((control) => {
2110 control.enable({ ...opts, onlySelf: true });
2111 });
2112 this.updateValueAndValidity({ onlySelf: true, emitEvent: opts.emitEvent });
2113 this._updateAncestors({ ...opts, skipPristineCheck });
2114 this._onDisabledChange.forEach((changeFn) => changeFn(false));
2115 }
2116 _updateAncestors(opts) {
2117 if (this._parent && !opts.onlySelf) {
2118 this._parent.updateValueAndValidity(opts);
2119 if (!opts.skipPristineCheck) {
2120 this._parent._updatePristine();
2121 }
2122 this._parent._updateTouched();
2123 }
2124 }
2125 /**
2126 * Sets the parent of the control
2127 *
2128 * @param parent The new parent.
2129 */
2130 setParent(parent) {
2131 this._parent = parent;
2132 }
2133 /**
2134 * The raw value of this control. For most control implementations, the raw value will include
2135 * disabled children.
2136 */
2137 getRawValue() {
2138 return this.value;
2139 }
2140 /**
2141 * Recalculates the value and validation status of the control.
2142 *
2143 * By default, it also updates the value and validity of its ancestors.
2144 *
2145 * @param opts Configuration options determine how the control propagates changes and emits events
2146 * after updates and validity checks are applied.
2147 * * `onlySelf`: When true, only update this control. When false or not supplied,
2148 * update all direct ancestors. Default is false.
2149 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
2150 * `valueChanges`
2151 * observables emit events with the latest status and value when the control is updated.
2152 * When false, no events are emitted.
2153 */
2154 updateValueAndValidity(opts = {}) {
2155 this._setInitialStatus();
2156 this._updateValue();
2157 if (this.enabled) {
2158 this._cancelExistingSubscription();
2159 this.errors = this._runValidator();
2160 this.status = this._calculateStatus();
2161 if (this.status === VALID || this.status === PENDING) {
2162 this._runAsyncValidator(opts.emitEvent);
2163 }
2164 }
2165 if (opts.emitEvent !== false) {
2166 this.valueChanges.emit(this.value);
2167 this.statusChanges.emit(this.status);
2168 }
2169 if (this._parent && !opts.onlySelf) {
2170 this._parent.updateValueAndValidity(opts);
2171 }
2172 }
2173 /** @internal */
2174 _updateTreeValidity(opts = { emitEvent: true }) {
2175 this._forEachChild((ctrl) => ctrl._updateTreeValidity(opts));
2176 this.updateValueAndValidity({ onlySelf: true, emitEvent: opts.emitEvent });
2177 }
2178 _setInitialStatus() {
2179 this.status = this._allControlsDisabled() ? DISABLED : VALID;
2180 }
2181 _runValidator() {
2182 return this.validator ? this.validator(this) : null;
2183 }
2184 _runAsyncValidator(emitEvent) {
2185 if (this.asyncValidator) {
2186 this.status = PENDING;
2187 this._hasOwnPendingAsyncValidator = true;
2188 const obs = toObservable(this.asyncValidator(this));
2189 this._asyncValidationSubscription = obs.subscribe((errors) => {
2190 this._hasOwnPendingAsyncValidator = false;
2191 // This will trigger the recalculation of the validation status, which depends on
2192 // the state of the asynchronous validation (whether it is in progress or not). So, it is
2193 // necessary that we have updated the `_hasOwnPendingAsyncValidator` boolean flag first.
2194 this.setErrors(errors, { emitEvent });
2195 });
2196 }
2197 }
2198 _cancelExistingSubscription() {
2199 if (this._asyncValidationSubscription) {
2200 this._asyncValidationSubscription.unsubscribe();
2201 this._hasOwnPendingAsyncValidator = false;
2202 }
2203 }
2204 /**
2205 * Sets errors on a form control when running validations manually, rather than automatically.
2206 *
2207 * Calling `setErrors` also updates the validity of the parent control.
2208 *
2209 * @param opts Configuration options that determine how the control propagates
2210 * changes and emits events after the control errors are set.
2211 * * `emitEvent`: When true or not supplied (the default), the `statusChanges`
2212 * observable emits an event after the errors are set.
2213 *
2214 * @usageNotes
2215 *
2216 * ### Manually set the errors for a control
2217 *
2218 * ```
2219 * const login = new FormControl('someLogin');
2220 * login.setErrors({
2221 * notUnique: true
2222 * });
2223 *
2224 * expect(login.valid).toEqual(false);
2225 * expect(login.errors).toEqual({ notUnique: true });
2226 *
2227 * login.setValue('someOtherLogin');
2228 *
2229 * expect(login.valid).toEqual(true);
2230 * ```
2231 */
2232 setErrors(errors, opts = {}) {
2233 this.errors = errors;
2234 this._updateControlsErrors(opts.emitEvent !== false);
2235 }
2236 /**
2237 * Retrieves a child control given the control's name or path.
2238 *
2239 * @param path A dot-delimited string or array of string/number values that define the path to the
2240 * control. If a string is provided, passing it as a string literal will result in improved type
2241 * information. Likewise, if an array is provided, passing it `as const` will cause improved type
2242 * information to be available.
2243 *
2244 * @usageNotes
2245 * ### Retrieve a nested control
2246 *
2247 * For example, to get a `name` control nested within a `person` sub-group:
2248 *
2249 * * `this.form.get('person.name');`
2250 *
2251 * -OR-
2252 *
2253 * * `this.form.get(['person', 'name'] as const);` // `as const` gives improved typings
2254 *
2255 * ### Retrieve a control in a FormArray
2256 *
2257 * When accessing an element inside a FormArray, you can use an element index.
2258 * For example, to get a `price` control from the first element in an `items` array you can use:
2259 *
2260 * * `this.form.get('items.0.price');`
2261 *
2262 * -OR-
2263 *
2264 * * `this.form.get(['items', 0, 'price']);`
2265 */
2266 get(path) {
2267 let currPath = path;
2268 if (currPath == null)
2269 return null;
2270 if (!Array.isArray(currPath))
2271 currPath = currPath.split('.');
2272 if (currPath.length === 0)
2273 return null;
2274 return currPath.reduce((control, name) => control && control._find(name), this);
2275 }
2276 /**
2277 * @description
2278 * Reports error data for the control with the given path.
2279 *
2280 * @param errorCode The code of the error to check
2281 * @param path A list of control names that designates how to move from the current control
2282 * to the control that should be queried for errors.
2283 *
2284 * @usageNotes
2285 * For example, for the following `FormGroup`:
2286 *
2287 * ```
2288 * form = new FormGroup({
2289 * address: new FormGroup({ street: new FormControl() })
2290 * });
2291 * ```
2292 *
2293 * The path to the 'street' control from the root form would be 'address' -> 'street'.
2294 *
2295 * It can be provided to this method in one of two formats:
2296 *
2297 * 1. An array of string control names, e.g. `['address', 'street']`
2298 * 1. A period-delimited list of control names in one string, e.g. `'address.street'`
2299 *
2300 * @returns error data for that particular error. If the control or error is not present,
2301 * null is returned.
2302 */
2303 getError(errorCode, path) {
2304 const control = path ? this.get(path) : this;
2305 return control && control.errors ? control.errors[errorCode] : null;
2306 }
2307 /**
2308 * @description
2309 * Reports whether the control with the given path has the error specified.
2310 *
2311 * @param errorCode The code of the error to check
2312 * @param path A list of control names that designates how to move from the current control
2313 * to the control that should be queried for errors.
2314 *
2315 * @usageNotes
2316 * For example, for the following `FormGroup`:
2317 *
2318 * ```
2319 * form = new FormGroup({
2320 * address: new FormGroup({ street: new FormControl() })
2321 * });
2322 * ```
2323 *
2324 * The path to the 'street' control from the root form would be 'address' -> 'street'.
2325 *
2326 * It can be provided to this method in one of two formats:
2327 *
2328 * 1. An array of string control names, e.g. `['address', 'street']`
2329 * 1. A period-delimited list of control names in one string, e.g. `'address.street'`
2330 *
2331 * If no path is given, this method checks for the error on the current control.
2332 *
2333 * @returns whether the given error is present in the control at the given path.
2334 *
2335 * If the control is not present, false is returned.
2336 */
2337 hasError(errorCode, path) {
2338 return !!this.getError(errorCode, path);
2339 }
2340 /**
2341 * Retrieves the top-level ancestor of this control.
2342 */
2343 get root() {
2344 let x = this;
2345 while (x._parent) {
2346 x = x._parent;
2347 }
2348 return x;
2349 }
2350 /** @internal */
2351 _updateControlsErrors(emitEvent) {
2352 this.status = this._calculateStatus();
2353 if (emitEvent) {
2354 this.statusChanges.emit(this.status);
2355 }
2356 if (this._parent) {
2357 this._parent._updateControlsErrors(emitEvent);
2358 }
2359 }
2360 /** @internal */
2361 _initObservables() {
2362 this.valueChanges = new EventEmitter();
2363 this.statusChanges = new EventEmitter();
2364 }
2365 _calculateStatus() {
2366 if (this._allControlsDisabled())
2367 return DISABLED;
2368 if (this.errors)
2369 return INVALID;
2370 if (this._hasOwnPendingAsyncValidator || this._anyControlsHaveStatus(PENDING))
2371 return PENDING;
2372 if (this._anyControlsHaveStatus(INVALID))
2373 return INVALID;
2374 return VALID;
2375 }
2376 /** @internal */
2377 _anyControlsHaveStatus(status) {
2378 return this._anyControls((control) => control.status === status);
2379 }
2380 /** @internal */
2381 _anyControlsDirty() {
2382 return this._anyControls((control) => control.dirty);
2383 }
2384 /** @internal */
2385 _anyControlsTouched() {
2386 return this._anyControls((control) => control.touched);
2387 }
2388 /** @internal */
2389 _updatePristine(opts = {}) {
2390 this.pristine = !this._anyControlsDirty();
2391 if (this._parent && !opts.onlySelf) {
2392 this._parent._updatePristine(opts);
2393 }
2394 }
2395 /** @internal */
2396 _updateTouched(opts = {}) {
2397 this.touched = this._anyControlsTouched();
2398 if (this._parent && !opts.onlySelf) {
2399 this._parent._updateTouched(opts);
2400 }
2401 }
2402 /** @internal */
2403 _registerOnCollectionChange(fn) {
2404 this._onCollectionChange = fn;
2405 }
2406 /** @internal */
2407 _setUpdateStrategy(opts) {
2408 if (isOptionsObj(opts) && opts.updateOn != null) {
2409 this._updateOn = opts.updateOn;
2410 }
2411 }
2412 /**
2413 * Check to see if parent has been marked artificially dirty.
2414 *
2415 * @internal
2416 */
2417 _parentMarkedDirty(onlySelf) {
2418 const parentDirty = this._parent && this._parent.dirty;
2419 return !onlySelf && !!parentDirty && !this._parent._anyControlsDirty();
2420 }
2421 /** @internal */
2422 _find(name) {
2423 return null;
2424 }
2425 /**
2426 * Internal implementation of the `setValidators` method. Needs to be separated out into a
2427 * different method, because it is called in the constructor and it can break cases where
2428 * a control is extended.
2429 */
2430 _assignValidators(validators) {
2431 this._rawValidators = Array.isArray(validators) ? validators.slice() : validators;
2432 this._composedValidatorFn = coerceToValidator(this._rawValidators);
2433 }
2434 /**
2435 * Internal implementation of the `setAsyncValidators` method. Needs to be separated out into a
2436 * different method, because it is called in the constructor and it can break cases where
2437 * a control is extended.
2438 */
2439 _assignAsyncValidators(validators) {
2440 this._rawAsyncValidators = Array.isArray(validators) ? validators.slice() : validators;
2441 this._composedAsyncValidatorFn = coerceToAsyncValidator(this._rawAsyncValidators);
2442 }
2443}
2444
2445/**
2446 * Tracks the value and validity state of a group of `FormControl` instances.
2447 *
2448 * A `FormGroup` aggregates the values of each child `FormControl` into one object,
2449 * with each control name as the key. It calculates its status by reducing the status values
2450 * of its children. For example, if one of the controls in a group is invalid, the entire
2451 * group becomes invalid.
2452 *
2453 * `FormGroup` is one of the four fundamental building blocks used to define forms in Angular,
2454 * along with `FormControl`, `FormArray`, and `FormRecord`.
2455 *
2456 * When instantiating a `FormGroup`, pass in a collection of child controls as the first
2457 * argument. The key for each child registers the name for the control.
2458 *
2459 * `FormGroup` is intended for use cases where the keys are known ahead of time.
2460 * If you need to dynamically add and remove controls, use {@link FormRecord} instead.
2461 *
2462 * `FormGroup` accepts an optional type parameter `TControl`, which is an object type with inner
2463 * control types as values.
2464 *
2465 * @usageNotes
2466 *
2467 * ### Create a form group with 2 controls
2468 *
2469 * ```
2470 * const form = new FormGroup({
2471 * first: new FormControl('Nancy', Validators.minLength(2)),
2472 * last: new FormControl('Drew'),
2473 * });
2474 *
2475 * console.log(form.value); // {first: 'Nancy', last; 'Drew'}
2476 * console.log(form.status); // 'VALID'
2477 * ```
2478 *
2479 * ### The type argument, and optional controls
2480 *
2481 * `FormGroup` accepts one generic argument, which is an object containing its inner controls.
2482 * This type will usually be inferred automatically, but you can always specify it explicitly if you
2483 * wish.
2484 *
2485 * If you have controls that are optional (i.e. they can be removed, you can use the `?` in the
2486 * type):
2487 *
2488 * ```
2489 * const form = new FormGroup<{
2490 * first: FormControl<string|null>,
2491 * middle?: FormControl<string|null>, // Middle name is optional.
2492 * last: FormControl<string|null>,
2493 * }>({
2494 * first: new FormControl('Nancy'),
2495 * last: new FormControl('Drew'),
2496 * });
2497 * ```
2498 *
2499 * ### Create a form group with a group-level validator
2500 *
2501 * You include group-level validators as the second arg, or group-level async
2502 * validators as the third arg. These come in handy when you want to perform validation
2503 * that considers the value of more than one child control.
2504 *
2505 * ```
2506 * const form = new FormGroup({
2507 * password: new FormControl('', Validators.minLength(2)),
2508 * passwordConfirm: new FormControl('', Validators.minLength(2)),
2509 * }, passwordMatchValidator);
2510 *
2511 *
2512 * function passwordMatchValidator(g: FormGroup) {
2513 * return g.get('password').value === g.get('passwordConfirm').value
2514 * ? null : {'mismatch': true};
2515 * }
2516 * ```
2517 *
2518 * Like `FormControl` instances, you choose to pass in
2519 * validators and async validators as part of an options object.
2520 *
2521 * ```
2522 * const form = new FormGroup({
2523 * password: new FormControl('')
2524 * passwordConfirm: new FormControl('')
2525 * }, { validators: passwordMatchValidator, asyncValidators: otherValidator });
2526 * ```
2527 *
2528 * ### Set the updateOn property for all controls in a form group
2529 *
2530 * The options object is used to set a default value for each child
2531 * control's `updateOn` property. If you set `updateOn` to `'blur'` at the
2532 * group level, all child controls default to 'blur', unless the child
2533 * has explicitly specified a different `updateOn` value.
2534 *
2535 * ```ts
2536 * const c = new FormGroup({
2537 * one: new FormControl()
2538 * }, { updateOn: 'blur' });
2539 * ```
2540 *
2541 * ### Using a FormGroup with optional controls
2542 *
2543 * It is possible to have optional controls in a FormGroup. An optional control can be removed later
2544 * using `removeControl`, and can be omitted when calling `reset`. Optional controls must be
2545 * declared optional in the group's type.
2546 *
2547 * ```ts
2548 * const c = new FormGroup<{one?: FormControl<string>}>({
2549 * one: new FormControl('')
2550 * });
2551 * ```
2552 *
2553 * Notice that `c.value.one` has type `string|null|undefined`. This is because calling `c.reset({})`
2554 * without providing the optional key `one` will cause it to become `null`.
2555 *
2556 * @publicApi
2557 */
2558class FormGroup extends AbstractControl {
2559 /**
2560 * Creates a new `FormGroup` instance.
2561 *
2562 * @param controls A collection of child controls. The key for each child is the name
2563 * under which it is registered.
2564 *
2565 * @param validatorOrOpts A synchronous validator function, or an array of
2566 * such functions, or an `AbstractControlOptions` object that contains validation functions
2567 * and a validation trigger.
2568 *
2569 * @param asyncValidator A single async validator or array of async validator functions
2570 *
2571 */
2572 constructor(controls, validatorOrOpts, asyncValidator) {
2573 super(pickValidators(validatorOrOpts), pickAsyncValidators(asyncValidator, validatorOrOpts));
2574 (typeof ngDevMode === 'undefined' || ngDevMode) && validateFormGroupControls(controls);
2575 this.controls = controls;
2576 this._initObservables();
2577 this._setUpdateStrategy(validatorOrOpts);
2578 this._setUpControls();
2579 this.updateValueAndValidity({
2580 onlySelf: true,
2581 // If `asyncValidator` is present, it will trigger control status change from `PENDING` to
2582 // `VALID` or `INVALID`. The status should be broadcasted via the `statusChanges` observable,
2583 // so we set `emitEvent` to `true` to allow that during the control creation process.
2584 emitEvent: !!this.asyncValidator
2585 });
2586 }
2587 registerControl(name, control) {
2588 if (this.controls[name])
2589 return this.controls[name];
2590 this.controls[name] = control;
2591 control.setParent(this);
2592 control._registerOnCollectionChange(this._onCollectionChange);
2593 return control;
2594 }
2595 addControl(name, control, options = {}) {
2596 this.registerControl(name, control);
2597 this.updateValueAndValidity({ emitEvent: options.emitEvent });
2598 this._onCollectionChange();
2599 }
2600 /**
2601 * Remove a control from this group. In a strongly-typed group, required controls cannot be
2602 * removed.
2603 *
2604 * This method also updates the value and validity of the control.
2605 *
2606 * @param name The control name to remove from the collection
2607 * @param options Specifies whether this FormGroup instance should emit events after a
2608 * control is removed.
2609 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
2610 * `valueChanges` observables emit events with the latest status and value when the control is
2611 * removed. When false, no events are emitted.
2612 */
2613 removeControl(name, options = {}) {
2614 if (this.controls[name])
2615 this.controls[name]._registerOnCollectionChange(() => { });
2616 delete (this.controls[name]);
2617 this.updateValueAndValidity({ emitEvent: options.emitEvent });
2618 this._onCollectionChange();
2619 }
2620 setControl(name, control, options = {}) {
2621 if (this.controls[name])
2622 this.controls[name]._registerOnCollectionChange(() => { });
2623 delete (this.controls[name]);
2624 if (control)
2625 this.registerControl(name, control);
2626 this.updateValueAndValidity({ emitEvent: options.emitEvent });
2627 this._onCollectionChange();
2628 }
2629 contains(controlName) {
2630 return this.controls.hasOwnProperty(controlName) && this.controls[controlName].enabled;
2631 }
2632 /**
2633 * Sets the value of the `FormGroup`. It accepts an object that matches
2634 * the structure of the group, with control names as keys.
2635 *
2636 * @usageNotes
2637 * ### Set the complete value for the form group
2638 *
2639 * ```
2640 * const form = new FormGroup({
2641 * first: new FormControl(),
2642 * last: new FormControl()
2643 * });
2644 *
2645 * console.log(form.value); // {first: null, last: null}
2646 *
2647 * form.setValue({first: 'Nancy', last: 'Drew'});
2648 * console.log(form.value); // {first: 'Nancy', last: 'Drew'}
2649 * ```
2650 *
2651 * @throws When strict checks fail, such as setting the value of a control
2652 * that doesn't exist or if you exclude a value of a control that does exist.
2653 *
2654 * @param value The new value for the control that matches the structure of the group.
2655 * @param options Configuration options that determine how the control propagates changes
2656 * and emits events after the value changes.
2657 * The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
2658 * updateValueAndValidity} method.
2659 *
2660 * * `onlySelf`: When true, each change only affects this control, and not its parent. Default is
2661 * false.
2662 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
2663 * `valueChanges`
2664 * observables emit events with the latest status and value when the control value is updated.
2665 * When false, no events are emitted.
2666 */
2667 setValue(value, options = {}) {
2668 assertAllValuesPresent(this, true, value);
2669 Object.keys(value).forEach(name => {
2670 assertControlPresent(this, true, name);
2671 this.controls[name].setValue(value[name], { onlySelf: true, emitEvent: options.emitEvent });
2672 });
2673 this.updateValueAndValidity(options);
2674 }
2675 /**
2676 * Patches the value of the `FormGroup`. It accepts an object with control
2677 * names as keys, and does its best to match the values to the correct controls
2678 * in the group.
2679 *
2680 * It accepts both super-sets and sub-sets of the group without throwing an error.
2681 *
2682 * @usageNotes
2683 * ### Patch the value for a form group
2684 *
2685 * ```
2686 * const form = new FormGroup({
2687 * first: new FormControl(),
2688 * last: new FormControl()
2689 * });
2690 * console.log(form.value); // {first: null, last: null}
2691 *
2692 * form.patchValue({first: 'Nancy'});
2693 * console.log(form.value); // {first: 'Nancy', last: null}
2694 * ```
2695 *
2696 * @param value The object that matches the structure of the group.
2697 * @param options Configuration options that determine how the control propagates changes and
2698 * emits events after the value is patched.
2699 * * `onlySelf`: When true, each change only affects this control and not its parent. Default is
2700 * true.
2701 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
2702 * `valueChanges` observables emit events with the latest status and value when the control value
2703 * is updated. When false, no events are emitted. The configuration options are passed to
2704 * the {@link AbstractControl#updateValueAndValidity updateValueAndValidity} method.
2705 */
2706 patchValue(value, options = {}) {
2707 // Even though the `value` argument type doesn't allow `null` and `undefined` values, the
2708 // `patchValue` can be called recursively and inner data structures might have these values, so
2709 // we just ignore such cases when a field containing FormGroup instance receives `null` or
2710 // `undefined` as a value.
2711 if (value == null /* both `null` and `undefined` */)
2712 return;
2713 Object.keys(value).forEach(name => {
2714 // The compiler cannot see through the uninstantiated conditional type of `this.controls`, so
2715 // `as any` is required.
2716 const control = this.controls[name];
2717 if (control) {
2718 control.patchValue(
2719 /* Guaranteed to be present, due to the outer forEach. */ value[name], { onlySelf: true, emitEvent: options.emitEvent });
2720 }
2721 });
2722 this.updateValueAndValidity(options);
2723 }
2724 /**
2725 * Resets the `FormGroup`, marks all descendants `pristine` and `untouched` and sets
2726 * the value of all descendants to their default values, or null if no defaults were provided.
2727 *
2728 * You reset to a specific form state by passing in a map of states
2729 * that matches the structure of your form, with control names as keys. The state
2730 * is a standalone value or a form state object with both a value and a disabled
2731 * status.
2732 *
2733 * @param value Resets the control with an initial value,
2734 * or an object that defines the initial value and disabled state.
2735 *
2736 * @param options Configuration options that determine how the control propagates changes
2737 * and emits events when the group is reset.
2738 * * `onlySelf`: When true, each change only affects this control, and not its parent. Default is
2739 * false.
2740 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
2741 * `valueChanges`
2742 * observables emit events with the latest status and value when the control is reset.
2743 * When false, no events are emitted.
2744 * The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
2745 * updateValueAndValidity} method.
2746 *
2747 * @usageNotes
2748 *
2749 * ### Reset the form group values
2750 *
2751 * ```ts
2752 * const form = new FormGroup({
2753 * first: new FormControl('first name'),
2754 * last: new FormControl('last name')
2755 * });
2756 *
2757 * console.log(form.value); // {first: 'first name', last: 'last name'}
2758 *
2759 * form.reset({ first: 'name', last: 'last name' });
2760 *
2761 * console.log(form.value); // {first: 'name', last: 'last name'}
2762 * ```
2763 *
2764 * ### Reset the form group values and disabled status
2765 *
2766 * ```
2767 * const form = new FormGroup({
2768 * first: new FormControl('first name'),
2769 * last: new FormControl('last name')
2770 * });
2771 *
2772 * form.reset({
2773 * first: {value: 'name', disabled: true},
2774 * last: 'last'
2775 * });
2776 *
2777 * console.log(form.value); // {last: 'last'}
2778 * console.log(form.get('first').status); // 'DISABLED'
2779 * ```
2780 */
2781 reset(value = {}, options = {}) {
2782 this._forEachChild((control, name) => {
2783 control.reset(value ? value[name] : null, { onlySelf: true, emitEvent: options.emitEvent });
2784 });
2785 this._updatePristine(options);
2786 this._updateTouched(options);
2787 this.updateValueAndValidity(options);
2788 }
2789 /**
2790 * The aggregate value of the `FormGroup`, including any disabled controls.
2791 *
2792 * Retrieves all values regardless of disabled status.
2793 */
2794 getRawValue() {
2795 return this._reduceChildren({}, (acc, control, name) => {
2796 acc[name] = control.getRawValue();
2797 return acc;
2798 });
2799 }
2800 /** @internal */
2801 _syncPendingControls() {
2802 let subtreeUpdated = this._reduceChildren(false, (updated, child) => {
2803 return child._syncPendingControls() ? true : updated;
2804 });
2805 if (subtreeUpdated)
2806 this.updateValueAndValidity({ onlySelf: true });
2807 return subtreeUpdated;
2808 }
2809 /** @internal */
2810 _forEachChild(cb) {
2811 Object.keys(this.controls).forEach(key => {
2812 // The list of controls can change (for ex. controls might be removed) while the loop
2813 // is running (as a result of invoking Forms API in `valueChanges` subscription), so we
2814 // have to null check before invoking the callback.
2815 const control = this.controls[key];
2816 control && cb(control, key);
2817 });
2818 }
2819 /** @internal */
2820 _setUpControls() {
2821 this._forEachChild((control) => {
2822 control.setParent(this);
2823 control._registerOnCollectionChange(this._onCollectionChange);
2824 });
2825 }
2826 /** @internal */
2827 _updateValue() {
2828 this.value = this._reduceValue();
2829 }
2830 /** @internal */
2831 _anyControls(condition) {
2832 for (const [controlName, control] of Object.entries(this.controls)) {
2833 if (this.contains(controlName) && condition(control)) {
2834 return true;
2835 }
2836 }
2837 return false;
2838 }
2839 /** @internal */
2840 _reduceValue() {
2841 let acc = {};
2842 return this._reduceChildren(acc, (acc, control, name) => {
2843 if (control.enabled || this.disabled) {
2844 acc[name] = control.value;
2845 }
2846 return acc;
2847 });
2848 }
2849 /** @internal */
2850 _reduceChildren(initValue, fn) {
2851 let res = initValue;
2852 this._forEachChild((control, name) => {
2853 res = fn(res, control, name);
2854 });
2855 return res;
2856 }
2857 /** @internal */
2858 _allControlsDisabled() {
2859 for (const controlName of Object.keys(this.controls)) {
2860 if (this.controls[controlName].enabled) {
2861 return false;
2862 }
2863 }
2864 return Object.keys(this.controls).length > 0 || this.disabled;
2865 }
2866 /** @internal */
2867 _find(name) {
2868 return this.controls.hasOwnProperty(name) ?
2869 this.controls[name] :
2870 null;
2871 }
2872}
2873/**
2874 * Will validate that none of the controls has a key with a dot
2875 * Throws other wise
2876 */
2877function validateFormGroupControls(controls) {
2878 const invalidKeys = Object.keys(controls).filter(key => key.includes('.'));
2879 if (invalidKeys.length > 0) {
2880 // TODO: make this an error once there are no more uses in G3
2881 console.warn(`FormGroup keys cannot include \`.\`, please replace the keys for: ${invalidKeys.join(',')}.`);
2882 }
2883}
2884const UntypedFormGroup = FormGroup;
2885/**
2886 * @description
2887 * Asserts that the given control is an instance of `FormGroup`
2888 *
2889 * @publicApi
2890 */
2891const isFormGroup = (control) => control instanceof FormGroup;
2892/**
2893 * Tracks the value and validity state of a collection of `FormControl` instances, each of which has
2894 * the same value type.
2895 *
2896 * `FormRecord` is very similar to {@link FormGroup}, except it can be used with a dynamic keys,
2897 * with controls added and removed as needed.
2898 *
2899 * `FormRecord` accepts one generic argument, which describes the type of the controls it contains.
2900 *
2901 * @usageNotes
2902 *
2903 * ```
2904 * let numbers = new FormRecord({bill: new FormControl('415-123-456')});
2905 * numbers.addControl('bob', new FormControl('415-234-567'));
2906 * numbers.removeControl('bill');
2907 * ```
2908 *
2909 * @publicApi
2910 */
2911class FormRecord extends FormGroup {
2912}
2913/**
2914 * @description
2915 * Asserts that the given control is an instance of `FormRecord`
2916 *
2917 * @publicApi
2918 */
2919const isFormRecord = (control) => control instanceof FormRecord;
2920
2921/**
2922 * Token to provide to allow SetDisabledState to always be called when a CVA is added, regardless of
2923 * whether the control is disabled or enabled.
2924 *
2925 * @see {@link FormsModule#withconfig}
2926 */
2927const CALL_SET_DISABLED_STATE = new InjectionToken('CallSetDisabledState', { providedIn: 'root', factory: () => setDisabledStateDefault });
2928/**
2929 * Whether to use the fixed setDisabledState behavior by default.
2930 */
2931const setDisabledStateDefault = 'always';
2932function controlPath(name, parent) {
2933 return [...parent.path, name];
2934}
2935/**
2936 * Links a Form control and a Form directive by setting up callbacks (such as `onChange`) on both
2937 * instances. This function is typically invoked when form directive is being initialized.
2938 *
2939 * @param control Form control instance that should be linked.
2940 * @param dir Directive that should be linked with a given control.
2941 */
2942function setUpControl(control, dir, callSetDisabledState = setDisabledStateDefault) {
2943 if (typeof ngDevMode === 'undefined' || ngDevMode) {
2944 if (!control)
2945 _throwError(dir, 'Cannot find control with');
2946 if (!dir.valueAccessor)
2947 _throwMissingValueAccessorError(dir);
2948 }
2949 setUpValidators(control, dir);
2950 dir.valueAccessor.writeValue(control.value);
2951 // The legacy behavior only calls the CVA's `setDisabledState` if the control is disabled.
2952 // If the `callSetDisabledState` option is set to `always`, then this bug is fixed and
2953 // the method is always called.
2954 if (control.disabled || callSetDisabledState === 'always') {
2955 dir.valueAccessor.setDisabledState?.(control.disabled);
2956 }
2957 setUpViewChangePipeline(control, dir);
2958 setUpModelChangePipeline(control, dir);
2959 setUpBlurPipeline(control, dir);
2960 setUpDisabledChangeHandler(control, dir);
2961}
2962/**
2963 * Reverts configuration performed by the `setUpControl` control function.
2964 * Effectively disconnects form control with a given form directive.
2965 * This function is typically invoked when corresponding form directive is being destroyed.
2966 *
2967 * @param control Form control which should be cleaned up.
2968 * @param dir Directive that should be disconnected from a given control.
2969 * @param validateControlPresenceOnChange Flag that indicates whether onChange handler should
2970 * contain asserts to verify that it's not called once directive is destroyed. We need this flag
2971 * to avoid potentially breaking changes caused by better control cleanup introduced in #39235.
2972 */
2973function cleanUpControl(control, dir, validateControlPresenceOnChange = true) {
2974 const noop = () => {
2975 if (validateControlPresenceOnChange && (typeof ngDevMode === 'undefined' || ngDevMode)) {
2976 _noControlError(dir);
2977 }
2978 };
2979 // The `valueAccessor` field is typically defined on FromControl and FormControlName directive
2980 // instances and there is a logic in `selectValueAccessor` function that throws if it's not the
2981 // case. We still check the presence of `valueAccessor` before invoking its methods to make sure
2982 // that cleanup works correctly if app code or tests are setup to ignore the error thrown from
2983 // `selectValueAccessor`. See https://github.com/angular/angular/issues/40521.
2984 if (dir.valueAccessor) {
2985 dir.valueAccessor.registerOnChange(noop);
2986 dir.valueAccessor.registerOnTouched(noop);
2987 }
2988 cleanUpValidators(control, dir);
2989 if (control) {
2990 dir._invokeOnDestroyCallbacks();
2991 control._registerOnCollectionChange(() => { });
2992 }
2993}
2994function registerOnValidatorChange(validators, onChange) {
2995 validators.forEach((validator) => {
2996 if (validator.registerOnValidatorChange)
2997 validator.registerOnValidatorChange(onChange);
2998 });
2999}
3000/**
3001 * Sets up disabled change handler function on a given form control if ControlValueAccessor
3002 * associated with a given directive instance supports the `setDisabledState` call.
3003 *
3004 * @param control Form control where disabled change handler should be setup.
3005 * @param dir Corresponding directive instance associated with this control.
3006 */
3007function setUpDisabledChangeHandler(control, dir) {
3008 if (dir.valueAccessor.setDisabledState) {
3009 const onDisabledChange = (isDisabled) => {
3010 dir.valueAccessor.setDisabledState(isDisabled);
3011 };
3012 control.registerOnDisabledChange(onDisabledChange);
3013 // Register a callback function to cleanup disabled change handler
3014 // from a control instance when a directive is destroyed.
3015 dir._registerOnDestroy(() => {
3016 control._unregisterOnDisabledChange(onDisabledChange);
3017 });
3018 }
3019}
3020/**
3021 * Sets up sync and async directive validators on provided form control.
3022 * This function merges validators from the directive into the validators of the control.
3023 *
3024 * @param control Form control where directive validators should be setup.
3025 * @param dir Directive instance that contains validators to be setup.
3026 */
3027function setUpValidators(control, dir) {
3028 const validators = getControlValidators(control);
3029 if (dir.validator !== null) {
3030 control.setValidators(mergeValidators(validators, dir.validator));
3031 }
3032 else if (typeof validators === 'function') {
3033 // If sync validators are represented by a single validator function, we force the
3034 // `Validators.compose` call to happen by executing the `setValidators` function with
3035 // an array that contains that function. We need this to avoid possible discrepancies in
3036 // validators behavior, so sync validators are always processed by the `Validators.compose`.
3037 // Note: we should consider moving this logic inside the `setValidators` function itself, so we
3038 // have consistent behavior on AbstractControl API level. The same applies to the async
3039 // validators logic below.
3040 control.setValidators([validators]);
3041 }
3042 const asyncValidators = getControlAsyncValidators(control);
3043 if (dir.asyncValidator !== null) {
3044 control.setAsyncValidators(mergeValidators(asyncValidators, dir.asyncValidator));
3045 }
3046 else if (typeof asyncValidators === 'function') {
3047 control.setAsyncValidators([asyncValidators]);
3048 }
3049 // Re-run validation when validator binding changes, e.g. minlength=3 -> minlength=4
3050 const onValidatorChange = () => control.updateValueAndValidity();
3051 registerOnValidatorChange(dir._rawValidators, onValidatorChange);
3052 registerOnValidatorChange(dir._rawAsyncValidators, onValidatorChange);
3053}
3054/**
3055 * Cleans up sync and async directive validators on provided form control.
3056 * This function reverts the setup performed by the `setUpValidators` function, i.e.
3057 * removes directive-specific validators from a given control instance.
3058 *
3059 * @param control Form control from where directive validators should be removed.
3060 * @param dir Directive instance that contains validators to be removed.
3061 * @returns true if a control was updated as a result of this action.
3062 */
3063function cleanUpValidators(control, dir) {
3064 let isControlUpdated = false;
3065 if (control !== null) {
3066 if (dir.validator !== null) {
3067 const validators = getControlValidators(control);
3068 if (Array.isArray(validators) && validators.length > 0) {
3069 // Filter out directive validator function.
3070 const updatedValidators = validators.filter((validator) => validator !== dir.validator);
3071 if (updatedValidators.length !== validators.length) {
3072 isControlUpdated = true;
3073 control.setValidators(updatedValidators);
3074 }
3075 }
3076 }
3077 if (dir.asyncValidator !== null) {
3078 const asyncValidators = getControlAsyncValidators(control);
3079 if (Array.isArray(asyncValidators) && asyncValidators.length > 0) {
3080 // Filter out directive async validator function.
3081 const updatedAsyncValidators = asyncValidators.filter((asyncValidator) => asyncValidator !== dir.asyncValidator);
3082 if (updatedAsyncValidators.length !== asyncValidators.length) {
3083 isControlUpdated = true;
3084 control.setAsyncValidators(updatedAsyncValidators);
3085 }
3086 }
3087 }
3088 }
3089 // Clear onValidatorChange callbacks by providing a noop function.
3090 const noop = () => { };
3091 registerOnValidatorChange(dir._rawValidators, noop);
3092 registerOnValidatorChange(dir._rawAsyncValidators, noop);
3093 return isControlUpdated;
3094}
3095function setUpViewChangePipeline(control, dir) {
3096 dir.valueAccessor.registerOnChange((newValue) => {
3097 control._pendingValue = newValue;
3098 control._pendingChange = true;
3099 control._pendingDirty = true;
3100 if (control.updateOn === 'change')
3101 updateControl(control, dir);
3102 });
3103}
3104function setUpBlurPipeline(control, dir) {
3105 dir.valueAccessor.registerOnTouched(() => {
3106 control._pendingTouched = true;
3107 if (control.updateOn === 'blur' && control._pendingChange)
3108 updateControl(control, dir);
3109 if (control.updateOn !== 'submit')
3110 control.markAsTouched();
3111 });
3112}
3113function updateControl(control, dir) {
3114 if (control._pendingDirty)
3115 control.markAsDirty();
3116 control.setValue(control._pendingValue, { emitModelToViewChange: false });
3117 dir.viewToModelUpdate(control._pendingValue);
3118 control._pendingChange = false;
3119}
3120function setUpModelChangePipeline(control, dir) {
3121 const onChange = (newValue, emitModelEvent) => {
3122 // control -> view
3123 dir.valueAccessor.writeValue(newValue);
3124 // control -> ngModel
3125 if (emitModelEvent)
3126 dir.viewToModelUpdate(newValue);
3127 };
3128 control.registerOnChange(onChange);
3129 // Register a callback function to cleanup onChange handler
3130 // from a control instance when a directive is destroyed.
3131 dir._registerOnDestroy(() => {
3132 control._unregisterOnChange(onChange);
3133 });
3134}
3135/**
3136 * Links a FormGroup or FormArray instance and corresponding Form directive by setting up validators
3137 * present in the view.
3138 *
3139 * @param control FormGroup or FormArray instance that should be linked.
3140 * @param dir Directive that provides view validators.
3141 */
3142function setUpFormContainer(control, dir) {
3143 if (control == null && (typeof ngDevMode === 'undefined' || ngDevMode))
3144 _throwError(dir, 'Cannot find control with');
3145 setUpValidators(control, dir);
3146}
3147/**
3148 * Reverts the setup performed by the `setUpFormContainer` function.
3149 *
3150 * @param control FormGroup or FormArray instance that should be cleaned up.
3151 * @param dir Directive that provided view validators.
3152 * @returns true if a control was updated as a result of this action.
3153 */
3154function cleanUpFormContainer(control, dir) {
3155 return cleanUpValidators(control, dir);
3156}
3157function _noControlError(dir) {
3158 return _throwError(dir, 'There is no FormControl instance attached to form control element with');
3159}
3160function _throwError(dir, message) {
3161 const messageEnd = _describeControlLocation(dir);
3162 throw new Error(`${message} ${messageEnd}`);
3163}
3164function _describeControlLocation(dir) {
3165 const path = dir.path;
3166 if (path && path.length > 1)
3167 return `path: '${path.join(' -> ')}'`;
3168 if (path?.[0])
3169 return `name: '${path}'`;
3170 return 'unspecified name attribute';
3171}
3172function _throwMissingValueAccessorError(dir) {
3173 const loc = _describeControlLocation(dir);
3174 throw new ɵRuntimeError(-1203 /* RuntimeErrorCode.NG_MISSING_VALUE_ACCESSOR */, `No value accessor for form control ${loc}.`);
3175}
3176function _throwInvalidValueAccessorError(dir) {
3177 const loc = _describeControlLocation(dir);
3178 throw new ɵRuntimeError(1200 /* RuntimeErrorCode.NG_VALUE_ACCESSOR_NOT_PROVIDED */, `Value accessor was not provided as an array for form control with ${loc}. ` +
3179 `Check that the \`NG_VALUE_ACCESSOR\` token is configured as a \`multi: true\` provider.`);
3180}
3181function isPropertyUpdated(changes, viewModel) {
3182 if (!changes.hasOwnProperty('model'))
3183 return false;
3184 const change = changes['model'];
3185 if (change.isFirstChange())
3186 return true;
3187 return !Object.is(viewModel, change.currentValue);
3188}
3189function isBuiltInAccessor(valueAccessor) {
3190 // Check if a given value accessor is an instance of a class that directly extends
3191 // `BuiltInControlValueAccessor` one.
3192 return Object.getPrototypeOf(valueAccessor.constructor) === BuiltInControlValueAccessor;
3193}
3194function syncPendingControls(form, directives) {
3195 form._syncPendingControls();
3196 directives.forEach((dir) => {
3197 const control = dir.control;
3198 if (control.updateOn === 'submit' && control._pendingChange) {
3199 dir.viewToModelUpdate(control._pendingValue);
3200 control._pendingChange = false;
3201 }
3202 });
3203}
3204// TODO: vsavkin remove it once https://github.com/angular/angular/issues/3011 is implemented
3205function selectValueAccessor(dir, valueAccessors) {
3206 if (!valueAccessors)
3207 return null;
3208 if (!Array.isArray(valueAccessors) && (typeof ngDevMode === 'undefined' || ngDevMode))
3209 _throwInvalidValueAccessorError(dir);
3210 let defaultAccessor = undefined;
3211 let builtinAccessor = undefined;
3212 let customAccessor = undefined;
3213 valueAccessors.forEach((v) => {
3214 if (v.constructor === DefaultValueAccessor) {
3215 defaultAccessor = v;
3216 }
3217 else if (isBuiltInAccessor(v)) {
3218 if (builtinAccessor && (typeof ngDevMode === 'undefined' || ngDevMode))
3219 _throwError(dir, 'More than one built-in value accessor matches form control with');
3220 builtinAccessor = v;
3221 }
3222 else {
3223 if (customAccessor && (typeof ngDevMode === 'undefined' || ngDevMode))
3224 _throwError(dir, 'More than one custom value accessor matches form control with');
3225 customAccessor = v;
3226 }
3227 });
3228 if (customAccessor)
3229 return customAccessor;
3230 if (builtinAccessor)
3231 return builtinAccessor;
3232 if (defaultAccessor)
3233 return defaultAccessor;
3234 if (typeof ngDevMode === 'undefined' || ngDevMode) {
3235 _throwError(dir, 'No valid value accessor for form control with');
3236 }
3237 return null;
3238}
3239function removeListItem$1(list, el) {
3240 const index = list.indexOf(el);
3241 if (index > -1)
3242 list.splice(index, 1);
3243}
3244// TODO(kara): remove after deprecation period
3245function _ngModelWarning(name, type, instance, warningConfig) {
3246 if (warningConfig === 'never')
3247 return;
3248 if (((warningConfig === null || warningConfig === 'once') && !type._ngModelWarningSentOnce) ||
3249 (warningConfig === 'always' && !instance._ngModelWarningSent)) {
3250 console.warn(ngModelWarning(name));
3251 type._ngModelWarningSentOnce = true;
3252 instance._ngModelWarningSent = true;
3253 }
3254}
3255
3256const formDirectiveProvider$1 = {
3257 provide: ControlContainer,
3258 useExisting: forwardRef(() => NgForm)
3259};
3260const resolvedPromise$1 = (() => Promise.resolve())();
3261/**
3262 * @description
3263 * Creates a top-level `FormGroup` instance and binds it to a form
3264 * to track aggregate form value and validation status.
3265 *
3266 * As soon as you import the `FormsModule`, this directive becomes active by default on
3267 * all `<form>` tags. You don't need to add a special selector.
3268 *
3269 * You optionally export the directive into a local template variable using `ngForm` as the key
3270 * (ex: `#myForm="ngForm"`). This is optional, but useful. Many properties from the underlying
3271 * `FormGroup` instance are duplicated on the directive itself, so a reference to it
3272 * gives you access to the aggregate value and validity status of the form, as well as
3273 * user interaction properties like `dirty` and `touched`.
3274 *
3275 * To register child controls with the form, use `NgModel` with a `name`
3276 * attribute. You may use `NgModelGroup` to create sub-groups within the form.
3277 *
3278 * If necessary, listen to the directive's `ngSubmit` event to be notified when the user has
3279 * triggered a form submission. The `ngSubmit` event emits the original form
3280 * submission event.
3281 *
3282 * In template driven forms, all `<form>` tags are automatically tagged as `NgForm`.
3283 * To import the `FormsModule` but skip its usage in some forms,
3284 * for example, to use native HTML5 validation, add the `ngNoForm` and the `<form>`
3285 * tags won't create an `NgForm` directive. In reactive forms, using `ngNoForm` is
3286 * unnecessary because the `<form>` tags are inert. In that case, you would
3287 * refrain from using the `formGroup` directive.
3288 *
3289 * @usageNotes
3290 *
3291 * ### Listening for form submission
3292 *
3293 * The following example shows how to capture the form values from the "ngSubmit" event.
3294 *
3295 * {@example forms/ts/simpleForm/simple_form_example.ts region='Component'}
3296 *
3297 * ### Setting the update options
3298 *
3299 * The following example shows you how to change the "updateOn" option from its default using
3300 * ngFormOptions.
3301 *
3302 * ```html
3303 * <form [ngFormOptions]="{updateOn: 'blur'}">
3304 * <input name="one" ngModel> <!-- this ngModel will update on blur -->
3305 * </form>
3306 * ```
3307 *
3308 * ### Native DOM validation UI
3309 *
3310 * In order to prevent the native DOM form validation UI from interfering with Angular's form
3311 * validation, Angular automatically adds the `novalidate` attribute on any `<form>` whenever
3312 * `FormModule` or `ReactiveFormModule` are imported into the application.
3313 * If you want to explicitly enable native DOM validation UI with Angular forms, you can add the
3314 * `ngNativeValidate` attribute to the `<form>` element:
3315 *
3316 * ```html
3317 * <form ngNativeValidate>
3318 * ...
3319 * </form>
3320 * ```
3321 *
3322 * @ngModule FormsModule
3323 * @publicApi
3324 */
3325class NgForm extends ControlContainer {
3326 constructor(validators, asyncValidators, callSetDisabledState) {
3327 super();
3328 this.callSetDisabledState = callSetDisabledState;
3329 /**
3330 * @description
3331 * Returns whether the form submission has been triggered.
3332 */
3333 this.submitted = false;
3334 this._directives = new Set();
3335 /**
3336 * @description
3337 * Event emitter for the "ngSubmit" event
3338 */
3339 this.ngSubmit = new EventEmitter();
3340 this.form =
3341 new FormGroup({}, composeValidators(validators), composeAsyncValidators(asyncValidators));
3342 }
3343 /** @nodoc */
3344 ngAfterViewInit() {
3345 this._setUpdateStrategy();
3346 }
3347 /**
3348 * @description
3349 * The directive instance.
3350 */
3351 get formDirective() {
3352 return this;
3353 }
3354 /**
3355 * @description
3356 * The internal `FormGroup` instance.
3357 */
3358 get control() {
3359 return this.form;
3360 }
3361 /**
3362 * @description
3363 * Returns an array representing the path to this group. Because this directive
3364 * always lives at the top level of a form, it is always an empty array.
3365 */
3366 get path() {
3367 return [];
3368 }
3369 /**
3370 * @description
3371 * Returns a map of the controls in this group.
3372 */
3373 get controls() {
3374 return this.form.controls;
3375 }
3376 /**
3377 * @description
3378 * Method that sets up the control directive in this group, re-calculates its value
3379 * and validity, and adds the instance to the internal list of directives.
3380 *
3381 * @param dir The `NgModel` directive instance.
3382 */
3383 addControl(dir) {
3384 resolvedPromise$1.then(() => {
3385 const container = this._findContainer(dir.path);
3386 dir.control =
3387 container.registerControl(dir.name, dir.control);
3388 setUpControl(dir.control, dir, this.callSetDisabledState);
3389 dir.control.updateValueAndValidity({ emitEvent: false });
3390 this._directives.add(dir);
3391 });
3392 }
3393 /**
3394 * @description
3395 * Retrieves the `FormControl` instance from the provided `NgModel` directive.
3396 *
3397 * @param dir The `NgModel` directive instance.
3398 */
3399 getControl(dir) {
3400 return this.form.get(dir.path);
3401 }
3402 /**
3403 * @description
3404 * Removes the `NgModel` instance from the internal list of directives
3405 *
3406 * @param dir The `NgModel` directive instance.
3407 */
3408 removeControl(dir) {
3409 resolvedPromise$1.then(() => {
3410 const container = this._findContainer(dir.path);
3411 if (container) {
3412 container.removeControl(dir.name);
3413 }
3414 this._directives.delete(dir);
3415 });
3416 }
3417 /**
3418 * @description
3419 * Adds a new `NgModelGroup` directive instance to the form.
3420 *
3421 * @param dir The `NgModelGroup` directive instance.
3422 */
3423 addFormGroup(dir) {
3424 resolvedPromise$1.then(() => {
3425 const container = this._findContainer(dir.path);
3426 const group = new FormGroup({});
3427 setUpFormContainer(group, dir);
3428 container.registerControl(dir.name, group);
3429 group.updateValueAndValidity({ emitEvent: false });
3430 });
3431 }
3432 /**
3433 * @description
3434 * Removes the `NgModelGroup` directive instance from the form.
3435 *
3436 * @param dir The `NgModelGroup` directive instance.
3437 */
3438 removeFormGroup(dir) {
3439 resolvedPromise$1.then(() => {
3440 const container = this._findContainer(dir.path);
3441 if (container) {
3442 container.removeControl(dir.name);
3443 }
3444 });
3445 }
3446 /**
3447 * @description
3448 * Retrieves the `FormGroup` for a provided `NgModelGroup` directive instance
3449 *
3450 * @param dir The `NgModelGroup` directive instance.
3451 */
3452 getFormGroup(dir) {
3453 return this.form.get(dir.path);
3454 }
3455 /**
3456 * Sets the new value for the provided `NgControl` directive.
3457 *
3458 * @param dir The `NgControl` directive instance.
3459 * @param value The new value for the directive's control.
3460 */
3461 updateModel(dir, value) {
3462 resolvedPromise$1.then(() => {
3463 const ctrl = this.form.get(dir.path);
3464 ctrl.setValue(value);
3465 });
3466 }
3467 /**
3468 * @description
3469 * Sets the value for this `FormGroup`.
3470 *
3471 * @param value The new value
3472 */
3473 setValue(value) {
3474 this.control.setValue(value);
3475 }
3476 /**
3477 * @description
3478 * Method called when the "submit" event is triggered on the form.
3479 * Triggers the `ngSubmit` emitter to emit the "submit" event as its payload.
3480 *
3481 * @param $event The "submit" event object
3482 */
3483 onSubmit($event) {
3484 this.submitted = true;
3485 syncPendingControls(this.form, this._directives);
3486 this.ngSubmit.emit($event);
3487 // Forms with `method="dialog"` have some special behavior
3488 // that won't reload the page and that shouldn't be prevented.
3489 return $event?.target?.method === 'dialog';
3490 }
3491 /**
3492 * @description
3493 * Method called when the "reset" event is triggered on the form.
3494 */
3495 onReset() {
3496 this.resetForm();
3497 }
3498 /**
3499 * @description
3500 * Resets the form to an initial value and resets its submitted status.
3501 *
3502 * @param value The new value for the form.
3503 */
3504 resetForm(value = undefined) {
3505 this.form.reset(value);
3506 this.submitted = false;
3507 }
3508 _setUpdateStrategy() {
3509 if (this.options && this.options.updateOn != null) {
3510 this.form._updateOn = this.options.updateOn;
3511 }
3512 }
3513 _findContainer(path) {
3514 path.pop();
3515 return path.length ? this.form.get(path) : this.form;
3516 }
3517 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NgForm, deps: [{ token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: CALL_SET_DISABLED_STATE, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
3518 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: { options: ["ngFormOptions", "options"] }, outputs: { ngSubmit: "ngSubmit" }, host: { listeners: { "submit": "onSubmit($event)", "reset": "onReset()" } }, providers: [formDirectiveProvider$1], exportAs: ["ngForm"], usesInheritance: true, ngImport: i0 }); }
3519}
3520i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NgForm, decorators: [{
3521 type: Directive,
3522 args: [{
3523 selector: 'form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]',
3524 providers: [formDirectiveProvider$1],
3525 host: { '(submit)': 'onSubmit($event)', '(reset)': 'onReset()' },
3526 outputs: ['ngSubmit'],
3527 exportAs: 'ngForm'
3528 }]
3529 }], ctorParameters: () => [{ type: undefined, decorators: [{
3530 type: Optional
3531 }, {
3532 type: Self
3533 }, {
3534 type: Inject,
3535 args: [NG_VALIDATORS]
3536 }] }, { type: undefined, decorators: [{
3537 type: Optional
3538 }, {
3539 type: Self
3540 }, {
3541 type: Inject,
3542 args: [NG_ASYNC_VALIDATORS]
3543 }] }, { type: undefined, decorators: [{
3544 type: Optional
3545 }, {
3546 type: Inject,
3547 args: [CALL_SET_DISABLED_STATE]
3548 }] }], propDecorators: { options: [{
3549 type: Input,
3550 args: ['ngFormOptions']
3551 }] } });
3552
3553function removeListItem(list, el) {
3554 const index = list.indexOf(el);
3555 if (index > -1)
3556 list.splice(index, 1);
3557}
3558
3559function isFormControlState(formState) {
3560 return typeof formState === 'object' && formState !== null &&
3561 Object.keys(formState).length === 2 && 'value' in formState && 'disabled' in formState;
3562}
3563const FormControl = (class FormControl extends AbstractControl {
3564 constructor(
3565 // formState and defaultValue will only be null if T is nullable
3566 formState = null, validatorOrOpts, asyncValidator) {
3567 super(pickValidators(validatorOrOpts), pickAsyncValidators(asyncValidator, validatorOrOpts));
3568 /** @publicApi */
3569 this.defaultValue = null;
3570 /** @internal */
3571 this._onChange = [];
3572 /** @internal */
3573 this._pendingChange = false;
3574 this._applyFormState(formState);
3575 this._setUpdateStrategy(validatorOrOpts);
3576 this._initObservables();
3577 this.updateValueAndValidity({
3578 onlySelf: true,
3579 // If `asyncValidator` is present, it will trigger control status change from `PENDING` to
3580 // `VALID` or `INVALID`.
3581 // The status should be broadcasted via the `statusChanges` observable, so we set
3582 // `emitEvent` to `true` to allow that during the control creation process.
3583 emitEvent: !!this.asyncValidator
3584 });
3585 if (isOptionsObj(validatorOrOpts) &&
3586 (validatorOrOpts.nonNullable || validatorOrOpts.initialValueIsDefault)) {
3587 if (isFormControlState(formState)) {
3588 this.defaultValue = formState.value;
3589 }
3590 else {
3591 this.defaultValue = formState;
3592 }
3593 }
3594 }
3595 setValue(value, options = {}) {
3596 this.value = this._pendingValue = value;
3597 if (this._onChange.length && options.emitModelToViewChange !== false) {
3598 this._onChange.forEach((changeFn) => changeFn(this.value, options.emitViewToModelChange !== false));
3599 }
3600 this.updateValueAndValidity(options);
3601 }
3602 patchValue(value, options = {}) {
3603 this.setValue(value, options);
3604 }
3605 reset(formState = this.defaultValue, options = {}) {
3606 this._applyFormState(formState);
3607 this.markAsPristine(options);
3608 this.markAsUntouched(options);
3609 this.setValue(this.value, options);
3610 this._pendingChange = false;
3611 }
3612 /** @internal */
3613 _updateValue() { }
3614 /** @internal */
3615 _anyControls(condition) {
3616 return false;
3617 }
3618 /** @internal */
3619 _allControlsDisabled() {
3620 return this.disabled;
3621 }
3622 registerOnChange(fn) {
3623 this._onChange.push(fn);
3624 }
3625 /** @internal */
3626 _unregisterOnChange(fn) {
3627 removeListItem(this._onChange, fn);
3628 }
3629 registerOnDisabledChange(fn) {
3630 this._onDisabledChange.push(fn);
3631 }
3632 /** @internal */
3633 _unregisterOnDisabledChange(fn) {
3634 removeListItem(this._onDisabledChange, fn);
3635 }
3636 /** @internal */
3637 _forEachChild(cb) { }
3638 /** @internal */
3639 _syncPendingControls() {
3640 if (this.updateOn === 'submit') {
3641 if (this._pendingDirty)
3642 this.markAsDirty();
3643 if (this._pendingTouched)
3644 this.markAsTouched();
3645 if (this._pendingChange) {
3646 this.setValue(this._pendingValue, { onlySelf: true, emitModelToViewChange: false });
3647 return true;
3648 }
3649 }
3650 return false;
3651 }
3652 _applyFormState(formState) {
3653 if (isFormControlState(formState)) {
3654 this.value = this._pendingValue = formState.value;
3655 formState.disabled ? this.disable({ onlySelf: true, emitEvent: false }) :
3656 this.enable({ onlySelf: true, emitEvent: false });
3657 }
3658 else {
3659 this.value = this._pendingValue = formState;
3660 }
3661 }
3662});
3663const UntypedFormControl = FormControl;
3664/**
3665 * @description
3666 * Asserts that the given control is an instance of `FormControl`
3667 *
3668 * @publicApi
3669 */
3670const isFormControl = (control) => control instanceof FormControl;
3671
3672/**
3673 * @description
3674 * A base class for code shared between the `NgModelGroup` and `FormGroupName` directives.
3675 *
3676 * @publicApi
3677 */
3678class AbstractFormGroupDirective extends ControlContainer {
3679 /** @nodoc */
3680 ngOnInit() {
3681 this._checkParentType();
3682 // Register the group with its parent group.
3683 this.formDirective.addFormGroup(this);
3684 }
3685 /** @nodoc */
3686 ngOnDestroy() {
3687 if (this.formDirective) {
3688 // Remove the group from its parent group.
3689 this.formDirective.removeFormGroup(this);
3690 }
3691 }
3692 /**
3693 * @description
3694 * The `FormGroup` bound to this directive.
3695 */
3696 get control() {
3697 return this.formDirective.getFormGroup(this);
3698 }
3699 /**
3700 * @description
3701 * The path to this group from the top-level directive.
3702 */
3703 get path() {
3704 return controlPath(this.name == null ? this.name : this.name.toString(), this._parent);
3705 }
3706 /**
3707 * @description
3708 * The top-level directive for this group if present, otherwise null.
3709 */
3710 get formDirective() {
3711 return this._parent ? this._parent.formDirective : null;
3712 }
3713 /** @internal */
3714 _checkParentType() { }
3715 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: AbstractFormGroupDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
3716 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: AbstractFormGroupDirective, usesInheritance: true, ngImport: i0 }); }
3717}
3718i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: AbstractFormGroupDirective, decorators: [{
3719 type: Directive
3720 }] });
3721
3722function modelParentException() {
3723 return new ɵRuntimeError(1350 /* RuntimeErrorCode.NGMODEL_IN_FORM_GROUP */, `
3724 ngModel cannot be used to register form controls with a parent formGroup directive. Try using
3725 formGroup's partner directive "formControlName" instead. Example:
3726
3727 ${formControlNameExample}
3728
3729 Or, if you'd like to avoid registering this form control, indicate that it's standalone in ngModelOptions:
3730
3731 Example:
3732
3733 ${ngModelWithFormGroupExample}`);
3734}
3735function formGroupNameException() {
3736 return new ɵRuntimeError(1351 /* RuntimeErrorCode.NGMODEL_IN_FORM_GROUP_NAME */, `
3737 ngModel cannot be used to register form controls with a parent formGroupName or formArrayName directive.
3738
3739 Option 1: Use formControlName instead of ngModel (reactive strategy):
3740
3741 ${formGroupNameExample}
3742
3743 Option 2: Update ngModel's parent be ngModelGroup (template-driven strategy):
3744
3745 ${ngModelGroupExample}`);
3746}
3747function missingNameException() {
3748 return new ɵRuntimeError(1352 /* RuntimeErrorCode.NGMODEL_WITHOUT_NAME */, `If ngModel is used within a form tag, either the name attribute must be set or the form
3749 control must be defined as 'standalone' in ngModelOptions.
3750
3751 Example 1: <input [(ngModel)]="person.firstName" name="first">
3752 Example 2: <input [(ngModel)]="person.firstName" [ngModelOptions]="{standalone: true}">`);
3753}
3754function modelGroupParentException() {
3755 return new ɵRuntimeError(1353 /* RuntimeErrorCode.NGMODELGROUP_IN_FORM_GROUP */, `
3756 ngModelGroup cannot be used with a parent formGroup directive.
3757
3758 Option 1: Use formGroupName instead of ngModelGroup (reactive strategy):
3759
3760 ${formGroupNameExample}
3761
3762 Option 2: Use a regular form tag instead of the formGroup directive (template-driven strategy):
3763
3764 ${ngModelGroupExample}`);
3765}
3766
3767const modelGroupProvider = {
3768 provide: ControlContainer,
3769 useExisting: forwardRef(() => NgModelGroup)
3770};
3771/**
3772 * @description
3773 * Creates and binds a `FormGroup` instance to a DOM element.
3774 *
3775 * This directive can only be used as a child of `NgForm` (within `<form>` tags).
3776 *
3777 * Use this directive to validate a sub-group of your form separately from the
3778 * rest of your form, or if some values in your domain model make more sense
3779 * to consume together in a nested object.
3780 *
3781 * Provide a name for the sub-group and it will become the key
3782 * for the sub-group in the form's full value. If you need direct access, export the directive into
3783 * a local template variable using `ngModelGroup` (ex: `#myGroup="ngModelGroup"`).
3784 *
3785 * @usageNotes
3786 *
3787 * ### Consuming controls in a grouping
3788 *
3789 * The following example shows you how to combine controls together in a sub-group
3790 * of the form.
3791 *
3792 * {@example forms/ts/ngModelGroup/ng_model_group_example.ts region='Component'}
3793 *
3794 * @ngModule FormsModule
3795 * @publicApi
3796 */
3797class NgModelGroup extends AbstractFormGroupDirective {
3798 constructor(parent, validators, asyncValidators) {
3799 super();
3800 /**
3801 * @description
3802 * Tracks the name of the `NgModelGroup` bound to the directive. The name corresponds
3803 * to a key in the parent `NgForm`.
3804 */
3805 this.name = '';
3806 this._parent = parent;
3807 this._setValidators(validators);
3808 this._setAsyncValidators(asyncValidators);
3809 }
3810 /** @internal */
3811 _checkParentType() {
3812 if (!(this._parent instanceof NgModelGroup) && !(this._parent instanceof NgForm) &&
3813 (typeof ngDevMode === 'undefined' || ngDevMode)) {
3814 throw modelGroupParentException();
3815 }
3816 }
3817 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NgModelGroup, deps: [{ token: ControlContainer, host: true, skipSelf: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive }); }
3818 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: NgModelGroup, selector: "[ngModelGroup]", inputs: { name: ["ngModelGroup", "name"] }, providers: [modelGroupProvider], exportAs: ["ngModelGroup"], usesInheritance: true, ngImport: i0 }); }
3819}
3820i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NgModelGroup, decorators: [{
3821 type: Directive,
3822 args: [{ selector: '[ngModelGroup]', providers: [modelGroupProvider], exportAs: 'ngModelGroup' }]
3823 }], ctorParameters: () => [{ type: ControlContainer, decorators: [{
3824 type: Host
3825 }, {
3826 type: SkipSelf
3827 }] }, { type: undefined, decorators: [{
3828 type: Optional
3829 }, {
3830 type: Self
3831 }, {
3832 type: Inject,
3833 args: [NG_VALIDATORS]
3834 }] }, { type: undefined, decorators: [{
3835 type: Optional
3836 }, {
3837 type: Self
3838 }, {
3839 type: Inject,
3840 args: [NG_ASYNC_VALIDATORS]
3841 }] }], propDecorators: { name: [{
3842 type: Input,
3843 args: ['ngModelGroup']
3844 }] } });
3845
3846const formControlBinding$1 = {
3847 provide: NgControl,
3848 useExisting: forwardRef(() => NgModel)
3849};
3850/**
3851 * `ngModel` forces an additional change detection run when its inputs change:
3852 * E.g.:
3853 * ```
3854 * <div>{{myModel.valid}}</div>
3855 * <input [(ngModel)]="myValue" #myModel="ngModel">
3856 * ```
3857 * I.e. `ngModel` can export itself on the element and then be used in the template.
3858 * Normally, this would result in expressions before the `input` that use the exported directive
3859 * to have an old value as they have been
3860 * dirty checked before. As this is a very common case for `ngModel`, we added this second change
3861 * detection run.
3862 *
3863 * Notes:
3864 * - this is just one extra run no matter how many `ngModel`s have been changed.
3865 * - this is a general problem when using `exportAs` for directives!
3866 */
3867const resolvedPromise = (() => Promise.resolve())();
3868/**
3869 * @description
3870 * Creates a `FormControl` instance from a [domain
3871 * model](https://en.wikipedia.org/wiki/Domain_model) and binds it to a form control element.
3872 *
3873 * The `FormControl` instance tracks the value, user interaction, and
3874 * validation status of the control and keeps the view synced with the model. If used
3875 * within a parent form, the directive also registers itself with the form as a child
3876 * control.
3877 *
3878 * This directive is used by itself or as part of a larger form. Use the
3879 * `ngModel` selector to activate it.
3880 *
3881 * It accepts a domain model as an optional `Input`. If you have a one-way binding
3882 * to `ngModel` with `[]` syntax, changing the domain model's value in the component
3883 * class sets the value in the view. If you have a two-way binding with `[()]` syntax
3884 * (also known as 'banana-in-a-box syntax'), the value in the UI always syncs back to
3885 * the domain model in your class.
3886 *
3887 * To inspect the properties of the associated `FormControl` (like the validity state),
3888 * export the directive into a local template variable using `ngModel` as the key (ex:
3889 * `#myVar="ngModel"`). You can then access the control using the directive's `control` property.
3890 * However, the most commonly used properties (like `valid` and `dirty`) also exist on the control
3891 * for direct access. See a full list of properties directly available in
3892 * `AbstractControlDirective`.
3893 *
3894 * @see {@link RadioControlValueAccessor}
3895 * @see {@link SelectControlValueAccessor}
3896 *
3897 * @usageNotes
3898 *
3899 * ### Using ngModel on a standalone control
3900 *
3901 * The following examples show a simple standalone control using `ngModel`:
3902 *
3903 * {@example forms/ts/simpleNgModel/simple_ng_model_example.ts region='Component'}
3904 *
3905 * When using the `ngModel` within `<form>` tags, you'll also need to supply a `name` attribute
3906 * so that the control can be registered with the parent form under that name.
3907 *
3908 * In the context of a parent form, it's often unnecessary to include one-way or two-way binding,
3909 * as the parent form syncs the value for you. You access its properties by exporting it into a
3910 * local template variable using `ngForm` such as (`#f="ngForm"`). Use the variable where
3911 * needed on form submission.
3912 *
3913 * If you do need to populate initial values into your form, using a one-way binding for
3914 * `ngModel` tends to be sufficient as long as you use the exported form's value rather
3915 * than the domain model's value on submit.
3916 *
3917 * ### Using ngModel within a form
3918 *
3919 * The following example shows controls using `ngModel` within a form:
3920 *
3921 * {@example forms/ts/simpleForm/simple_form_example.ts region='Component'}
3922 *
3923 * ### Using a standalone ngModel within a group
3924 *
3925 * The following example shows you how to use a standalone ngModel control
3926 * within a form. This controls the display of the form, but doesn't contain form data.
3927 *
3928 * ```html
3929 * <form>
3930 * <input name="login" ngModel placeholder="Login">
3931 * <input type="checkbox" ngModel [ngModelOptions]="{standalone: true}"> Show more options?
3932 * </form>
3933 * <!-- form value: {login: ''} -->
3934 * ```
3935 *
3936 * ### Setting the ngModel `name` attribute through options
3937 *
3938 * The following example shows you an alternate way to set the name attribute. Here,
3939 * an attribute identified as name is used within a custom form control component. To still be able
3940 * to specify the NgModel's name, you must specify it using the `ngModelOptions` input instead.
3941 *
3942 * ```html
3943 * <form>
3944 * <my-custom-form-control name="Nancy" ngModel [ngModelOptions]="{name: 'user'}">
3945 * </my-custom-form-control>
3946 * </form>
3947 * <!-- form value: {user: ''} -->
3948 * ```
3949 *
3950 * @ngModule FormsModule
3951 * @publicApi
3952 */
3953class NgModel extends NgControl {
3954 constructor(parent, validators, asyncValidators, valueAccessors, _changeDetectorRef, callSetDisabledState) {
3955 super();
3956 this._changeDetectorRef = _changeDetectorRef;
3957 this.callSetDisabledState = callSetDisabledState;
3958 this.control = new FormControl();
3959 /** @internal */
3960 this._registered = false;
3961 /**
3962 * @description
3963 * Tracks the name bound to the directive. If a parent form exists, it
3964 * uses this name as a key to retrieve this control's value.
3965 */
3966 this.name = '';
3967 /**
3968 * @description
3969 * Event emitter for producing the `ngModelChange` event after
3970 * the view model updates.
3971 */
3972 this.update = new EventEmitter();
3973 this._parent = parent;
3974 this._setValidators(validators);
3975 this._setAsyncValidators(asyncValidators);
3976 this.valueAccessor = selectValueAccessor(this, valueAccessors);
3977 }
3978 /** @nodoc */
3979 ngOnChanges(changes) {
3980 this._checkForErrors();
3981 if (!this._registered || 'name' in changes) {
3982 if (this._registered) {
3983 this._checkName();
3984 if (this.formDirective) {
3985 // We can't call `formDirective.removeControl(this)`, because the `name` has already been
3986 // changed. We also can't reset the name temporarily since the logic in `removeControl`
3987 // is inside a promise and it won't run immediately. We work around it by giving it an
3988 // object with the same shape instead.
3989 const oldName = changes['name'].previousValue;
3990 this.formDirective.removeControl({ name: oldName, path: this._getPath(oldName) });
3991 }
3992 }
3993 this._setUpControl();
3994 }
3995 if ('isDisabled' in changes) {
3996 this._updateDisabled(changes);
3997 }
3998 if (isPropertyUpdated(changes, this.viewModel)) {
3999 this._updateValue(this.model);
4000 this.viewModel = this.model;
4001 }
4002 }
4003 /** @nodoc */
4004 ngOnDestroy() {
4005 this.formDirective && this.formDirective.removeControl(this);
4006 }
4007 /**
4008 * @description
4009 * Returns an array that represents the path from the top-level form to this control.
4010 * Each index is the string name of the control on that level.
4011 */
4012 get path() {
4013 return this._getPath(this.name);
4014 }
4015 /**
4016 * @description
4017 * The top-level directive for this control if present, otherwise null.
4018 */
4019 get formDirective() {
4020 return this._parent ? this._parent.formDirective : null;
4021 }
4022 /**
4023 * @description
4024 * Sets the new value for the view model and emits an `ngModelChange` event.
4025 *
4026 * @param newValue The new value emitted by `ngModelChange`.
4027 */
4028 viewToModelUpdate(newValue) {
4029 this.viewModel = newValue;
4030 this.update.emit(newValue);
4031 }
4032 _setUpControl() {
4033 this._setUpdateStrategy();
4034 this._isStandalone() ? this._setUpStandalone() : this.formDirective.addControl(this);
4035 this._registered = true;
4036 }
4037 _setUpdateStrategy() {
4038 if (this.options && this.options.updateOn != null) {
4039 this.control._updateOn = this.options.updateOn;
4040 }
4041 }
4042 _isStandalone() {
4043 return !this._parent || !!(this.options && this.options.standalone);
4044 }
4045 _setUpStandalone() {
4046 setUpControl(this.control, this, this.callSetDisabledState);
4047 this.control.updateValueAndValidity({ emitEvent: false });
4048 }
4049 _checkForErrors() {
4050 if (!this._isStandalone()) {
4051 this._checkParentType();
4052 }
4053 this._checkName();
4054 }
4055 _checkParentType() {
4056 if (typeof ngDevMode === 'undefined' || ngDevMode) {
4057 if (!(this._parent instanceof NgModelGroup) &&
4058 this._parent instanceof AbstractFormGroupDirective) {
4059 throw formGroupNameException();
4060 }
4061 else if (!(this._parent instanceof NgModelGroup) && !(this._parent instanceof NgForm)) {
4062 throw modelParentException();
4063 }
4064 }
4065 }
4066 _checkName() {
4067 if (this.options && this.options.name)
4068 this.name = this.options.name;
4069 if (!this._isStandalone() && !this.name && (typeof ngDevMode === 'undefined' || ngDevMode)) {
4070 throw missingNameException();
4071 }
4072 }
4073 _updateValue(value) {
4074 resolvedPromise.then(() => {
4075 this.control.setValue(value, { emitViewToModelChange: false });
4076 this._changeDetectorRef?.markForCheck();
4077 });
4078 }
4079 _updateDisabled(changes) {
4080 const disabledValue = changes['isDisabled'].currentValue;
4081 // checking for 0 to avoid breaking change
4082 const isDisabled = disabledValue !== 0 && booleanAttribute(disabledValue);
4083 resolvedPromise.then(() => {
4084 if (isDisabled && !this.control.disabled) {
4085 this.control.disable();
4086 }
4087 else if (!isDisabled && this.control.disabled) {
4088 this.control.enable();
4089 }
4090 this._changeDetectorRef?.markForCheck();
4091 });
4092 }
4093 _getPath(controlName) {
4094 return this._parent ? controlPath(controlName, this._parent) : [controlName];
4095 }
4096 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NgModel, deps: [{ token: ControlContainer, host: true, optional: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: NG_VALUE_ACCESSOR, optional: true, self: true }, { token: ChangeDetectorRef, optional: true }, { token: CALL_SET_DISABLED_STATE, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
4097 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: { name: "name", isDisabled: ["disabled", "isDisabled"], model: ["ngModel", "model"], options: ["ngModelOptions", "options"] }, outputs: { update: "ngModelChange" }, providers: [formControlBinding$1], exportAs: ["ngModel"], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
4098}
4099i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NgModel, decorators: [{
4100 type: Directive,
4101 args: [{
4102 selector: '[ngModel]:not([formControlName]):not([formControl])',
4103 providers: [formControlBinding$1],
4104 exportAs: 'ngModel'
4105 }]
4106 }], ctorParameters: () => [{ type: ControlContainer, decorators: [{
4107 type: Optional
4108 }, {
4109 type: Host
4110 }] }, { type: undefined, decorators: [{
4111 type: Optional
4112 }, {
4113 type: Self
4114 }, {
4115 type: Inject,
4116 args: [NG_VALIDATORS]
4117 }] }, { type: undefined, decorators: [{
4118 type: Optional
4119 }, {
4120 type: Self
4121 }, {
4122 type: Inject,
4123 args: [NG_ASYNC_VALIDATORS]
4124 }] }, { type: undefined, decorators: [{
4125 type: Optional
4126 }, {
4127 type: Self
4128 }, {
4129 type: Inject,
4130 args: [NG_VALUE_ACCESSOR]
4131 }] }, { type: i0.ChangeDetectorRef, decorators: [{
4132 type: Optional
4133 }, {
4134 type: Inject,
4135 args: [ChangeDetectorRef]
4136 }] }, { type: undefined, decorators: [{
4137 type: Optional
4138 }, {
4139 type: Inject,
4140 args: [CALL_SET_DISABLED_STATE]
4141 }] }], propDecorators: { name: [{
4142 type: Input
4143 }], isDisabled: [{
4144 type: Input,
4145 args: ['disabled']
4146 }], model: [{
4147 type: Input,
4148 args: ['ngModel']
4149 }], options: [{
4150 type: Input,
4151 args: ['ngModelOptions']
4152 }], update: [{
4153 type: Output,
4154 args: ['ngModelChange']
4155 }] } });
4156
4157/**
4158 * @description
4159 *
4160 * Adds `novalidate` attribute to all forms by default.
4161 *
4162 * `novalidate` is used to disable browser's native form validation.
4163 *
4164 * If you want to use native validation with Angular forms, just add `ngNativeValidate` attribute:
4165 *
4166 * ```
4167 * <form ngNativeValidate></form>
4168 * ```
4169 *
4170 * @publicApi
4171 * @ngModule ReactiveFormsModule
4172 * @ngModule FormsModule
4173 */
4174class ɵNgNoValidate {
4175 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ɵNgNoValidate, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4176 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])", host: { attributes: { "novalidate": "" } }, ngImport: i0 }); }
4177}
4178i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ɵNgNoValidate, decorators: [{
4179 type: Directive,
4180 args: [{
4181 selector: 'form:not([ngNoForm]):not([ngNativeValidate])',
4182 host: { 'novalidate': '' },
4183 }]
4184 }] });
4185
4186const NUMBER_VALUE_ACCESSOR = {
4187 provide: NG_VALUE_ACCESSOR,
4188 useExisting: forwardRef(() => NumberValueAccessor),
4189 multi: true
4190};
4191/**
4192 * @description
4193 * The `ControlValueAccessor` for writing a number value and listening to number input changes.
4194 * The value accessor is used by the `FormControlDirective`, `FormControlName`, and `NgModel`
4195 * directives.
4196 *
4197 * @usageNotes
4198 *
4199 * ### Using a number input with a reactive form.
4200 *
4201 * The following example shows how to use a number input with a reactive form.
4202 *
4203 * ```ts
4204 * const totalCountControl = new FormControl();
4205 * ```
4206 *
4207 * ```
4208 * <input type="number" [formControl]="totalCountControl">
4209 * ```
4210 *
4211 * @ngModule ReactiveFormsModule
4212 * @ngModule FormsModule
4213 * @publicApi
4214 */
4215class NumberValueAccessor extends BuiltInControlValueAccessor {
4216 /**
4217 * Sets the "value" property on the input element.
4218 * @nodoc
4219 */
4220 writeValue(value) {
4221 // The value needs to be normalized for IE9, otherwise it is set to 'null' when null
4222 const normalizedValue = value == null ? '' : value;
4223 this.setProperty('value', normalizedValue);
4224 }
4225 /**
4226 * Registers a function called when the control value changes.
4227 * @nodoc
4228 */
4229 registerOnChange(fn) {
4230 this.onChange = (value) => {
4231 fn(value == '' ? null : parseFloat(value));
4232 };
4233 }
4234 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NumberValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
4235 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]", host: { listeners: { "input": "onChange($event.target.value)", "blur": "onTouched()" } }, providers: [NUMBER_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 }); }
4236}
4237i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NumberValueAccessor, decorators: [{
4238 type: Directive,
4239 args: [{
4240 selector: 'input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]',
4241 host: { '(input)': 'onChange($event.target.value)', '(blur)': 'onTouched()' },
4242 providers: [NUMBER_VALUE_ACCESSOR]
4243 }]
4244 }] });
4245
4246const RADIO_VALUE_ACCESSOR = {
4247 provide: NG_VALUE_ACCESSOR,
4248 useExisting: forwardRef(() => RadioControlValueAccessor),
4249 multi: true
4250};
4251function throwNameError() {
4252 throw new ɵRuntimeError(1202 /* RuntimeErrorCode.NAME_AND_FORM_CONTROL_NAME_MUST_MATCH */, `
4253 If you define both a name and a formControlName attribute on your radio button, their values
4254 must match. Ex: <input type="radio" formControlName="food" name="food">
4255 `);
4256}
4257/**
4258 * @description
4259 * Class used by Angular to track radio buttons. For internal use only.
4260 */
4261class RadioControlRegistry {
4262 constructor() {
4263 this._accessors = [];
4264 }
4265 /**
4266 * @description
4267 * Adds a control to the internal registry. For internal use only.
4268 */
4269 add(control, accessor) {
4270 this._accessors.push([control, accessor]);
4271 }
4272 /**
4273 * @description
4274 * Removes a control from the internal registry. For internal use only.
4275 */
4276 remove(accessor) {
4277 for (let i = this._accessors.length - 1; i >= 0; --i) {
4278 if (this._accessors[i][1] === accessor) {
4279 this._accessors.splice(i, 1);
4280 return;
4281 }
4282 }
4283 }
4284 /**
4285 * @description
4286 * Selects a radio button. For internal use only.
4287 */
4288 select(accessor) {
4289 this._accessors.forEach((c) => {
4290 if (this._isSameGroup(c, accessor) && c[1] !== accessor) {
4291 c[1].fireUncheck(accessor.value);
4292 }
4293 });
4294 }
4295 _isSameGroup(controlPair, accessor) {
4296 if (!controlPair[0].control)
4297 return false;
4298 return controlPair[0]._parent === accessor._control._parent &&
4299 controlPair[1].name === accessor.name;
4300 }
4301 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: RadioControlRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4302 static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: RadioControlRegistry, providedIn: 'root' }); }
4303}
4304i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: RadioControlRegistry, decorators: [{
4305 type: Injectable,
4306 args: [{ providedIn: 'root' }]
4307 }] });
4308/**
4309 * @description
4310 * The `ControlValueAccessor` for writing radio control values and listening to radio control
4311 * changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
4312 * `NgModel` directives.
4313 *
4314 * @usageNotes
4315 *
4316 * ### Using radio buttons with reactive form directives
4317 *
4318 * The follow example shows how to use radio buttons in a reactive form. When using radio buttons in
4319 * a reactive form, radio buttons in the same group should have the same `formControlName`.
4320 * Providing a `name` attribute is optional.
4321 *
4322 * {@example forms/ts/reactiveRadioButtons/reactive_radio_button_example.ts region='Reactive'}
4323 *
4324 * @ngModule ReactiveFormsModule
4325 * @ngModule FormsModule
4326 * @publicApi
4327 */
4328class RadioControlValueAccessor extends BuiltInControlValueAccessor {
4329 constructor(renderer, elementRef, _registry, _injector) {
4330 super(renderer, elementRef);
4331 this._registry = _registry;
4332 this._injector = _injector;
4333 this.setDisabledStateFired = false;
4334 /**
4335 * The registered callback function called when a change event occurs on the input element.
4336 * Note: we declare `onChange` here (also used as host listener) as a function with no arguments
4337 * to override the `onChange` function (which expects 1 argument) in the parent
4338 * `BaseControlValueAccessor` class.
4339 * @nodoc
4340 */
4341 this.onChange = () => { };
4342 this.callSetDisabledState = inject(CALL_SET_DISABLED_STATE, { optional: true }) ?? setDisabledStateDefault;
4343 }
4344 /** @nodoc */
4345 ngOnInit() {
4346 this._control = this._injector.get(NgControl);
4347 this._checkName();
4348 this._registry.add(this._control, this);
4349 }
4350 /** @nodoc */
4351 ngOnDestroy() {
4352 this._registry.remove(this);
4353 }
4354 /**
4355 * Sets the "checked" property value on the radio input element.
4356 * @nodoc
4357 */
4358 writeValue(value) {
4359 this._state = value === this.value;
4360 this.setProperty('checked', this._state);
4361 }
4362 /**
4363 * Registers a function called when the control value changes.
4364 * @nodoc
4365 */
4366 registerOnChange(fn) {
4367 this._fn = fn;
4368 this.onChange = () => {
4369 fn(this.value);
4370 this._registry.select(this);
4371 };
4372 }
4373 /** @nodoc */
4374 setDisabledState(isDisabled) {
4375 /**
4376 * `setDisabledState` is supposed to be called whenever the disabled state of a control changes,
4377 * including upon control creation. However, a longstanding bug caused the method to not fire
4378 * when an *enabled* control was attached. This bug was fixed in v15 in #47576.
4379 *
4380 * This had a side effect: previously, it was possible to instantiate a reactive form control
4381 * with `[attr.disabled]=true`, even though the corresponding control was enabled in the
4382 * model. This resulted in a mismatch between the model and the DOM. Now, because
4383 * `setDisabledState` is always called, the value in the DOM will be immediately overwritten
4384 * with the "correct" enabled value.
4385 *
4386 * However, the fix also created an exceptional case: radio buttons. Because Reactive Forms
4387 * models the entire group of radio buttons as a single `FormControl`, there is no way to
4388 * control the disabled state for individual radios, so they can no longer be configured as
4389 * disabled. Thus, we keep the old behavior for radio buttons, so that `[attr.disabled]`
4390 * continues to work. Specifically, we drop the first call to `setDisabledState` if `disabled`
4391 * is `false`, and we are not in legacy mode.
4392 */
4393 if (this.setDisabledStateFired || isDisabled ||
4394 this.callSetDisabledState === 'whenDisabledForLegacyCode') {
4395 this.setProperty('disabled', isDisabled);
4396 }
4397 this.setDisabledStateFired = true;
4398 }
4399 /**
4400 * Sets the "value" on the radio input element and unchecks it.
4401 *
4402 * @param value
4403 */
4404 fireUncheck(value) {
4405 this.writeValue(value);
4406 }
4407 _checkName() {
4408 if (this.name && this.formControlName && this.name !== this.formControlName &&
4409 (typeof ngDevMode === 'undefined' || ngDevMode)) {
4410 throwNameError();
4411 }
4412 if (!this.name && this.formControlName)
4413 this.name = this.formControlName;
4414 }
4415 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: RadioControlValueAccessor, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }, { token: RadioControlRegistry }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Directive }); }
4416 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: { name: "name", formControlName: "formControlName", value: "value" }, host: { listeners: { "change": "onChange()", "blur": "onTouched()" } }, providers: [RADIO_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 }); }
4417}
4418i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: RadioControlValueAccessor, decorators: [{
4419 type: Directive,
4420 args: [{
4421 selector: 'input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]',
4422 host: { '(change)': 'onChange()', '(blur)': 'onTouched()' },
4423 providers: [RADIO_VALUE_ACCESSOR]
4424 }]
4425 }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }, { type: RadioControlRegistry }, { type: i0.Injector }], propDecorators: { name: [{
4426 type: Input
4427 }], formControlName: [{
4428 type: Input
4429 }], value: [{
4430 type: Input
4431 }] } });
4432
4433const RANGE_VALUE_ACCESSOR = {
4434 provide: NG_VALUE_ACCESSOR,
4435 useExisting: forwardRef(() => RangeValueAccessor),
4436 multi: true
4437};
4438/**
4439 * @description
4440 * The `ControlValueAccessor` for writing a range value and listening to range input changes.
4441 * The value accessor is used by the `FormControlDirective`, `FormControlName`, and `NgModel`
4442 * directives.
4443 *
4444 * @usageNotes
4445 *
4446 * ### Using a range input with a reactive form
4447 *
4448 * The following example shows how to use a range input with a reactive form.
4449 *
4450 * ```ts
4451 * const ageControl = new FormControl();
4452 * ```
4453 *
4454 * ```
4455 * <input type="range" [formControl]="ageControl">
4456 * ```
4457 *
4458 * @ngModule ReactiveFormsModule
4459 * @ngModule FormsModule
4460 * @publicApi
4461 */
4462class RangeValueAccessor extends BuiltInControlValueAccessor {
4463 /**
4464 * Sets the "value" property on the input element.
4465 * @nodoc
4466 */
4467 writeValue(value) {
4468 this.setProperty('value', parseFloat(value));
4469 }
4470 /**
4471 * Registers a function called when the control value changes.
4472 * @nodoc
4473 */
4474 registerOnChange(fn) {
4475 this.onChange = (value) => {
4476 fn(value == '' ? null : parseFloat(value));
4477 };
4478 }
4479 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: RangeValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
4480 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]", host: { listeners: { "change": "onChange($event.target.value)", "input": "onChange($event.target.value)", "blur": "onTouched()" } }, providers: [RANGE_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 }); }
4481}
4482i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: RangeValueAccessor, decorators: [{
4483 type: Directive,
4484 args: [{
4485 selector: 'input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]',
4486 host: {
4487 '(change)': 'onChange($event.target.value)',
4488 '(input)': 'onChange($event.target.value)',
4489 '(blur)': 'onTouched()'
4490 },
4491 providers: [RANGE_VALUE_ACCESSOR]
4492 }]
4493 }] });
4494
4495/**
4496 * Token to provide to turn off the ngModel warning on formControl and formControlName.
4497 */
4498const NG_MODEL_WITH_FORM_CONTROL_WARNING = new InjectionToken(ngDevMode ? 'NgModelWithFormControlWarning' : '');
4499const formControlBinding = {
4500 provide: NgControl,
4501 useExisting: forwardRef(() => FormControlDirective)
4502};
4503/**
4504 * @description
4505 * Synchronizes a standalone `FormControl` instance to a form control element.
4506 *
4507 * Note that support for using the `ngModel` input property and `ngModelChange` event with reactive
4508 * form directives was deprecated in Angular v6 and is scheduled for removal in
4509 * a future version of Angular.
4510 * For details, see [Deprecated features](guide/deprecations#ngmodel-with-reactive-forms).
4511 *
4512 * @see [Reactive Forms Guide](guide/reactive-forms)
4513 * @see {@link FormControl}
4514 * @see {@link AbstractControl}
4515 *
4516 * @usageNotes
4517 *
4518 * The following example shows how to register a standalone control and set its value.
4519 *
4520 * {@example forms/ts/simpleFormControl/simple_form_control_example.ts region='Component'}
4521 *
4522 * @ngModule ReactiveFormsModule
4523 * @publicApi
4524 */
4525class FormControlDirective extends NgControl {
4526 /**
4527 * @description
4528 * Triggers a warning in dev mode that this input should not be used with reactive forms.
4529 */
4530 set isDisabled(isDisabled) {
4531 if (typeof ngDevMode === 'undefined' || ngDevMode) {
4532 console.warn(disabledAttrWarning);
4533 }
4534 }
4535 /**
4536 * @description
4537 * Static property used to track whether any ngModel warnings have been sent across
4538 * all instances of FormControlDirective. Used to support warning config of "once".
4539 *
4540 * @internal
4541 */
4542 static { this._ngModelWarningSentOnce = false; }
4543 constructor(validators, asyncValidators, valueAccessors, _ngModelWarningConfig, callSetDisabledState) {
4544 super();
4545 this._ngModelWarningConfig = _ngModelWarningConfig;
4546 this.callSetDisabledState = callSetDisabledState;
4547 /** @deprecated as of v6 */
4548 this.update = new EventEmitter();
4549 /**
4550 * @description
4551 * Instance property used to track whether an ngModel warning has been sent out for this
4552 * particular `FormControlDirective` instance. Used to support warning config of "always".
4553 *
4554 * @internal
4555 */
4556 this._ngModelWarningSent = false;
4557 this._setValidators(validators);
4558 this._setAsyncValidators(asyncValidators);
4559 this.valueAccessor = selectValueAccessor(this, valueAccessors);
4560 }
4561 /** @nodoc */
4562 ngOnChanges(changes) {
4563 if (this._isControlChanged(changes)) {
4564 const previousForm = changes['form'].previousValue;
4565 if (previousForm) {
4566 cleanUpControl(previousForm, this, /* validateControlPresenceOnChange */ false);
4567 }
4568 setUpControl(this.form, this, this.callSetDisabledState);
4569 this.form.updateValueAndValidity({ emitEvent: false });
4570 }
4571 if (isPropertyUpdated(changes, this.viewModel)) {
4572 if (typeof ngDevMode === 'undefined' || ngDevMode) {
4573 _ngModelWarning('formControl', FormControlDirective, this, this._ngModelWarningConfig);
4574 }
4575 this.form.setValue(this.model);
4576 this.viewModel = this.model;
4577 }
4578 }
4579 /** @nodoc */
4580 ngOnDestroy() {
4581 if (this.form) {
4582 cleanUpControl(this.form, this, /* validateControlPresenceOnChange */ false);
4583 }
4584 }
4585 /**
4586 * @description
4587 * Returns an array that represents the path from the top-level form to this control.
4588 * Each index is the string name of the control on that level.
4589 */
4590 get path() {
4591 return [];
4592 }
4593 /**
4594 * @description
4595 * The `FormControl` bound to this directive.
4596 */
4597 get control() {
4598 return this.form;
4599 }
4600 /**
4601 * @description
4602 * Sets the new value for the view model and emits an `ngModelChange` event.
4603 *
4604 * @param newValue The new value for the view model.
4605 */
4606 viewToModelUpdate(newValue) {
4607 this.viewModel = newValue;
4608 this.update.emit(newValue);
4609 }
4610 _isControlChanged(changes) {
4611 return changes.hasOwnProperty('form');
4612 }
4613 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormControlDirective, deps: [{ token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: NG_VALUE_ACCESSOR, optional: true, self: true }, { token: NG_MODEL_WITH_FORM_CONTROL_WARNING, optional: true }, { token: CALL_SET_DISABLED_STATE, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
4614 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: FormControlDirective, selector: "[formControl]", inputs: { form: ["formControl", "form"], isDisabled: ["disabled", "isDisabled"], model: ["ngModel", "model"] }, outputs: { update: "ngModelChange" }, providers: [formControlBinding], exportAs: ["ngForm"], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
4615}
4616i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormControlDirective, decorators: [{
4617 type: Directive,
4618 args: [{ selector: '[formControl]', providers: [formControlBinding], exportAs: 'ngForm' }]
4619 }], ctorParameters: () => [{ type: undefined, decorators: [{
4620 type: Optional
4621 }, {
4622 type: Self
4623 }, {
4624 type: Inject,
4625 args: [NG_VALIDATORS]
4626 }] }, { type: undefined, decorators: [{
4627 type: Optional
4628 }, {
4629 type: Self
4630 }, {
4631 type: Inject,
4632 args: [NG_ASYNC_VALIDATORS]
4633 }] }, { type: undefined, decorators: [{
4634 type: Optional
4635 }, {
4636 type: Self
4637 }, {
4638 type: Inject,
4639 args: [NG_VALUE_ACCESSOR]
4640 }] }, { type: undefined, decorators: [{
4641 type: Optional
4642 }, {
4643 type: Inject,
4644 args: [NG_MODEL_WITH_FORM_CONTROL_WARNING]
4645 }] }, { type: undefined, decorators: [{
4646 type: Optional
4647 }, {
4648 type: Inject,
4649 args: [CALL_SET_DISABLED_STATE]
4650 }] }], propDecorators: { form: [{
4651 type: Input,
4652 args: ['formControl']
4653 }], isDisabled: [{
4654 type: Input,
4655 args: ['disabled']
4656 }], model: [{
4657 type: Input,
4658 args: ['ngModel']
4659 }], update: [{
4660 type: Output,
4661 args: ['ngModelChange']
4662 }] } });
4663
4664const formDirectiveProvider = {
4665 provide: ControlContainer,
4666 useExisting: forwardRef(() => FormGroupDirective)
4667};
4668/**
4669 * @description
4670 *
4671 * Binds an existing `FormGroup` or `FormRecord` to a DOM element.
4672 *
4673 * This directive accepts an existing `FormGroup` instance. It will then use this
4674 * `FormGroup` instance to match any child `FormControl`, `FormGroup`/`FormRecord`,
4675 * and `FormArray` instances to child `FormControlName`, `FormGroupName`,
4676 * and `FormArrayName` directives.
4677 *
4678 * @see [Reactive Forms Guide](guide/reactive-forms)
4679 * @see {@link AbstractControl}
4680 *
4681 * @usageNotes
4682 * ### Register Form Group
4683 *
4684 * The following example registers a `FormGroup` with first name and last name controls,
4685 * and listens for the *ngSubmit* event when the button is clicked.
4686 *
4687 * {@example forms/ts/simpleFormGroup/simple_form_group_example.ts region='Component'}
4688 *
4689 * @ngModule ReactiveFormsModule
4690 * @publicApi
4691 */
4692class FormGroupDirective extends ControlContainer {
4693 constructor(validators, asyncValidators, callSetDisabledState) {
4694 super();
4695 this.callSetDisabledState = callSetDisabledState;
4696 /**
4697 * @description
4698 * Reports whether the form submission has been triggered.
4699 */
4700 this.submitted = false;
4701 /**
4702 * Callback that should be invoked when controls in FormGroup or FormArray collection change
4703 * (added or removed). This callback triggers corresponding DOM updates.
4704 */
4705 this._onCollectionChange = () => this._updateDomValue();
4706 /**
4707 * @description
4708 * Tracks the list of added `FormControlName` instances
4709 */
4710 this.directives = [];
4711 /**
4712 * @description
4713 * Tracks the `FormGroup` bound to this directive.
4714 */
4715 this.form = null;
4716 /**
4717 * @description
4718 * Emits an event when the form submission has been triggered.
4719 */
4720 this.ngSubmit = new EventEmitter();
4721 this._setValidators(validators);
4722 this._setAsyncValidators(asyncValidators);
4723 }
4724 /** @nodoc */
4725 ngOnChanges(changes) {
4726 this._checkFormPresent();
4727 if (changes.hasOwnProperty('form')) {
4728 this._updateValidators();
4729 this._updateDomValue();
4730 this._updateRegistrations();
4731 this._oldForm = this.form;
4732 }
4733 }
4734 /** @nodoc */
4735 ngOnDestroy() {
4736 if (this.form) {
4737 cleanUpValidators(this.form, this);
4738 // Currently the `onCollectionChange` callback is rewritten each time the
4739 // `_registerOnCollectionChange` function is invoked. The implication is that cleanup should
4740 // happen *only* when the `onCollectionChange` callback was set by this directive instance.
4741 // Otherwise it might cause overriding a callback of some other directive instances. We should
4742 // consider updating this logic later to make it similar to how `onChange` callbacks are
4743 // handled, see https://github.com/angular/angular/issues/39732 for additional info.
4744 if (this.form._onCollectionChange === this._onCollectionChange) {
4745 this.form._registerOnCollectionChange(() => { });
4746 }
4747 }
4748 }
4749 /**
4750 * @description
4751 * Returns this directive's instance.
4752 */
4753 get formDirective() {
4754 return this;
4755 }
4756 /**
4757 * @description
4758 * Returns the `FormGroup` bound to this directive.
4759 */
4760 get control() {
4761 return this.form;
4762 }
4763 /**
4764 * @description
4765 * Returns an array representing the path to this group. Because this directive
4766 * always lives at the top level of a form, it always an empty array.
4767 */
4768 get path() {
4769 return [];
4770 }
4771 /**
4772 * @description
4773 * Method that sets up the control directive in this group, re-calculates its value
4774 * and validity, and adds the instance to the internal list of directives.
4775 *
4776 * @param dir The `FormControlName` directive instance.
4777 */
4778 addControl(dir) {
4779 const ctrl = this.form.get(dir.path);
4780 setUpControl(ctrl, dir, this.callSetDisabledState);
4781 ctrl.updateValueAndValidity({ emitEvent: false });
4782 this.directives.push(dir);
4783 return ctrl;
4784 }
4785 /**
4786 * @description
4787 * Retrieves the `FormControl` instance from the provided `FormControlName` directive
4788 *
4789 * @param dir The `FormControlName` directive instance.
4790 */
4791 getControl(dir) {
4792 return this.form.get(dir.path);
4793 }
4794 /**
4795 * @description
4796 * Removes the `FormControlName` instance from the internal list of directives
4797 *
4798 * @param dir The `FormControlName` directive instance.
4799 */
4800 removeControl(dir) {
4801 cleanUpControl(dir.control || null, dir, /* validateControlPresenceOnChange */ false);
4802 removeListItem$1(this.directives, dir);
4803 }
4804 /**
4805 * Adds a new `FormGroupName` directive instance to the form.
4806 *
4807 * @param dir The `FormGroupName` directive instance.
4808 */
4809 addFormGroup(dir) {
4810 this._setUpFormContainer(dir);
4811 }
4812 /**
4813 * Performs the necessary cleanup when a `FormGroupName` directive instance is removed from the
4814 * view.
4815 *
4816 * @param dir The `FormGroupName` directive instance.
4817 */
4818 removeFormGroup(dir) {
4819 this._cleanUpFormContainer(dir);
4820 }
4821 /**
4822 * @description
4823 * Retrieves the `FormGroup` for a provided `FormGroupName` directive instance
4824 *
4825 * @param dir The `FormGroupName` directive instance.
4826 */
4827 getFormGroup(dir) {
4828 return this.form.get(dir.path);
4829 }
4830 /**
4831 * Performs the necessary setup when a `FormArrayName` directive instance is added to the view.
4832 *
4833 * @param dir The `FormArrayName` directive instance.
4834 */
4835 addFormArray(dir) {
4836 this._setUpFormContainer(dir);
4837 }
4838 /**
4839 * Performs the necessary cleanup when a `FormArrayName` directive instance is removed from the
4840 * view.
4841 *
4842 * @param dir The `FormArrayName` directive instance.
4843 */
4844 removeFormArray(dir) {
4845 this._cleanUpFormContainer(dir);
4846 }
4847 /**
4848 * @description
4849 * Retrieves the `FormArray` for a provided `FormArrayName` directive instance.
4850 *
4851 * @param dir The `FormArrayName` directive instance.
4852 */
4853 getFormArray(dir) {
4854 return this.form.get(dir.path);
4855 }
4856 /**
4857 * Sets the new value for the provided `FormControlName` directive.
4858 *
4859 * @param dir The `FormControlName` directive instance.
4860 * @param value The new value for the directive's control.
4861 */
4862 updateModel(dir, value) {
4863 const ctrl = this.form.get(dir.path);
4864 ctrl.setValue(value);
4865 }
4866 /**
4867 * @description
4868 * Method called with the "submit" event is triggered on the form.
4869 * Triggers the `ngSubmit` emitter to emit the "submit" event as its payload.
4870 *
4871 * @param $event The "submit" event object
4872 */
4873 onSubmit($event) {
4874 this.submitted = true;
4875 syncPendingControls(this.form, this.directives);
4876 this.ngSubmit.emit($event);
4877 // Forms with `method="dialog"` have some special behavior that won't reload the page and that
4878 // shouldn't be prevented. Note that we need to null check the `event` and the `target`, because
4879 // some internal apps call this method directly with the wrong arguments.
4880 return $event?.target?.method === 'dialog';
4881 }
4882 /**
4883 * @description
4884 * Method called when the "reset" event is triggered on the form.
4885 */
4886 onReset() {
4887 this.resetForm();
4888 }
4889 /**
4890 * @description
4891 * Resets the form to an initial value and resets its submitted status.
4892 *
4893 * @param value The new value for the form.
4894 */
4895 resetForm(value = undefined) {
4896 this.form.reset(value);
4897 this.submitted = false;
4898 }
4899 /** @internal */
4900 _updateDomValue() {
4901 this.directives.forEach(dir => {
4902 const oldCtrl = dir.control;
4903 const newCtrl = this.form.get(dir.path);
4904 if (oldCtrl !== newCtrl) {
4905 // Note: the value of the `dir.control` may not be defined, for example when it's a first
4906 // `FormControl` that is added to a `FormGroup` instance (via `addControl` call).
4907 cleanUpControl(oldCtrl || null, dir);
4908 // Check whether new control at the same location inside the corresponding `FormGroup` is an
4909 // instance of `FormControl` and perform control setup only if that's the case.
4910 // Note: we don't need to clear the list of directives (`this.directives`) here, it would be
4911 // taken care of in the `removeControl` method invoked when corresponding `formControlName`
4912 // directive instance is being removed (invoked from `FormControlName.ngOnDestroy`).
4913 if (isFormControl(newCtrl)) {
4914 setUpControl(newCtrl, dir, this.callSetDisabledState);
4915 dir.control = newCtrl;
4916 }
4917 }
4918 });
4919 this.form._updateTreeValidity({ emitEvent: false });
4920 }
4921 _setUpFormContainer(dir) {
4922 const ctrl = this.form.get(dir.path);
4923 setUpFormContainer(ctrl, dir);
4924 // NOTE: this operation looks unnecessary in case no new validators were added in
4925 // `setUpFormContainer` call. Consider updating this code to match the logic in
4926 // `_cleanUpFormContainer` function.
4927 ctrl.updateValueAndValidity({ emitEvent: false });
4928 }
4929 _cleanUpFormContainer(dir) {
4930 if (this.form) {
4931 const ctrl = this.form.get(dir.path);
4932 if (ctrl) {
4933 const isControlUpdated = cleanUpFormContainer(ctrl, dir);
4934 if (isControlUpdated) {
4935 // Run validity check only in case a control was updated (i.e. view validators were
4936 // removed) as removing view validators might cause validity to change.
4937 ctrl.updateValueAndValidity({ emitEvent: false });
4938 }
4939 }
4940 }
4941 }
4942 _updateRegistrations() {
4943 this.form._registerOnCollectionChange(this._onCollectionChange);
4944 if (this._oldForm) {
4945 this._oldForm._registerOnCollectionChange(() => { });
4946 }
4947 }
4948 _updateValidators() {
4949 setUpValidators(this.form, this);
4950 if (this._oldForm) {
4951 cleanUpValidators(this._oldForm, this);
4952 }
4953 }
4954 _checkFormPresent() {
4955 if (!this.form && (typeof ngDevMode === 'undefined' || ngDevMode)) {
4956 throw missingFormException();
4957 }
4958 }
4959 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormGroupDirective, deps: [{ token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: CALL_SET_DISABLED_STATE, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
4960 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: FormGroupDirective, selector: "[formGroup]", inputs: { form: ["formGroup", "form"] }, outputs: { ngSubmit: "ngSubmit" }, host: { listeners: { "submit": "onSubmit($event)", "reset": "onReset()" } }, providers: [formDirectiveProvider], exportAs: ["ngForm"], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
4961}
4962i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormGroupDirective, decorators: [{
4963 type: Directive,
4964 args: [{
4965 selector: '[formGroup]',
4966 providers: [formDirectiveProvider],
4967 host: { '(submit)': 'onSubmit($event)', '(reset)': 'onReset()' },
4968 exportAs: 'ngForm'
4969 }]
4970 }], ctorParameters: () => [{ type: undefined, decorators: [{
4971 type: Optional
4972 }, {
4973 type: Self
4974 }, {
4975 type: Inject,
4976 args: [NG_VALIDATORS]
4977 }] }, { type: undefined, decorators: [{
4978 type: Optional
4979 }, {
4980 type: Self
4981 }, {
4982 type: Inject,
4983 args: [NG_ASYNC_VALIDATORS]
4984 }] }, { type: undefined, decorators: [{
4985 type: Optional
4986 }, {
4987 type: Inject,
4988 args: [CALL_SET_DISABLED_STATE]
4989 }] }], propDecorators: { form: [{
4990 type: Input,
4991 args: ['formGroup']
4992 }], ngSubmit: [{
4993 type: Output
4994 }] } });
4995
4996const formGroupNameProvider = {
4997 provide: ControlContainer,
4998 useExisting: forwardRef(() => FormGroupName)
4999};
5000/**
5001 * @description
5002 *
5003 * Syncs a nested `FormGroup` or `FormRecord` to a DOM element.
5004 *
5005 * This directive can only be used with a parent `FormGroupDirective`.
5006 *
5007 * It accepts the string name of the nested `FormGroup` or `FormRecord` to link, and
5008 * looks for a `FormGroup` or `FormRecord` registered with that name in the parent
5009 * `FormGroup` instance you passed into `FormGroupDirective`.
5010 *
5011 * Use nested form groups to validate a sub-group of a
5012 * form separately from the rest or to group the values of certain
5013 * controls into their own nested object.
5014 *
5015 * @see [Reactive Forms Guide](guide/reactive-forms)
5016 *
5017 * @usageNotes
5018 *
5019 * ### Access the group by name
5020 *
5021 * The following example uses the `AbstractControl.get` method to access the
5022 * associated `FormGroup`
5023 *
5024 * ```ts
5025 * this.form.get('name');
5026 * ```
5027 *
5028 * ### Access individual controls in the group
5029 *
5030 * The following example uses the `AbstractControl.get` method to access
5031 * individual controls within the group using dot syntax.
5032 *
5033 * ```ts
5034 * this.form.get('name.first');
5035 * ```
5036 *
5037 * ### Register a nested `FormGroup`.
5038 *
5039 * The following example registers a nested *name* `FormGroup` within an existing `FormGroup`,
5040 * and provides methods to retrieve the nested `FormGroup` and individual controls.
5041 *
5042 * {@example forms/ts/nestedFormGroup/nested_form_group_example.ts region='Component'}
5043 *
5044 * @ngModule ReactiveFormsModule
5045 * @publicApi
5046 */
5047class FormGroupName extends AbstractFormGroupDirective {
5048 constructor(parent, validators, asyncValidators) {
5049 super();
5050 /**
5051 * @description
5052 * Tracks the name of the `FormGroup` bound to the directive. The name corresponds
5053 * to a key in the parent `FormGroup` or `FormArray`.
5054 * Accepts a name as a string or a number.
5055 * The name in the form of a string is useful for individual forms,
5056 * while the numerical form allows for form groups to be bound
5057 * to indices when iterating over groups in a `FormArray`.
5058 */
5059 this.name = null;
5060 this._parent = parent;
5061 this._setValidators(validators);
5062 this._setAsyncValidators(asyncValidators);
5063 }
5064 /** @internal */
5065 _checkParentType() {
5066 if (_hasInvalidParent(this._parent) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
5067 throw groupParentException();
5068 }
5069 }
5070 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormGroupName, deps: [{ token: ControlContainer, host: true, optional: true, skipSelf: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive }); }
5071 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: FormGroupName, selector: "[formGroupName]", inputs: { name: ["formGroupName", "name"] }, providers: [formGroupNameProvider], usesInheritance: true, ngImport: i0 }); }
5072}
5073i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormGroupName, decorators: [{
5074 type: Directive,
5075 args: [{ selector: '[formGroupName]', providers: [formGroupNameProvider] }]
5076 }], ctorParameters: () => [{ type: ControlContainer, decorators: [{
5077 type: Optional
5078 }, {
5079 type: Host
5080 }, {
5081 type: SkipSelf
5082 }] }, { type: undefined, decorators: [{
5083 type: Optional
5084 }, {
5085 type: Self
5086 }, {
5087 type: Inject,
5088 args: [NG_VALIDATORS]
5089 }] }, { type: undefined, decorators: [{
5090 type: Optional
5091 }, {
5092 type: Self
5093 }, {
5094 type: Inject,
5095 args: [NG_ASYNC_VALIDATORS]
5096 }] }], propDecorators: { name: [{
5097 type: Input,
5098 args: ['formGroupName']
5099 }] } });
5100const formArrayNameProvider = {
5101 provide: ControlContainer,
5102 useExisting: forwardRef(() => FormArrayName)
5103};
5104/**
5105 * @description
5106 *
5107 * Syncs a nested `FormArray` to a DOM element.
5108 *
5109 * This directive is designed to be used with a parent `FormGroupDirective` (selector:
5110 * `[formGroup]`).
5111 *
5112 * It accepts the string name of the nested `FormArray` you want to link, and
5113 * will look for a `FormArray` registered with that name in the parent
5114 * `FormGroup` instance you passed into `FormGroupDirective`.
5115 *
5116 * @see [Reactive Forms Guide](guide/reactive-forms)
5117 * @see {@link AbstractControl}
5118 *
5119 * @usageNotes
5120 *
5121 * ### Example
5122 *
5123 * {@example forms/ts/nestedFormArray/nested_form_array_example.ts region='Component'}
5124 *
5125 * @ngModule ReactiveFormsModule
5126 * @publicApi
5127 */
5128class FormArrayName extends ControlContainer {
5129 constructor(parent, validators, asyncValidators) {
5130 super();
5131 /**
5132 * @description
5133 * Tracks the name of the `FormArray` bound to the directive. The name corresponds
5134 * to a key in the parent `FormGroup` or `FormArray`.
5135 * Accepts a name as a string or a number.
5136 * The name in the form of a string is useful for individual forms,
5137 * while the numerical form allows for form arrays to be bound
5138 * to indices when iterating over arrays in a `FormArray`.
5139 */
5140 this.name = null;
5141 this._parent = parent;
5142 this._setValidators(validators);
5143 this._setAsyncValidators(asyncValidators);
5144 }
5145 /**
5146 * A lifecycle method called when the directive's inputs are initialized. For internal use only.
5147 * @throws If the directive does not have a valid parent.
5148 * @nodoc
5149 */
5150 ngOnInit() {
5151 this._checkParentType();
5152 this.formDirective.addFormArray(this);
5153 }
5154 /**
5155 * A lifecycle method called before the directive's instance is destroyed. For internal use only.
5156 * @nodoc
5157 */
5158 ngOnDestroy() {
5159 if (this.formDirective) {
5160 this.formDirective.removeFormArray(this);
5161 }
5162 }
5163 /**
5164 * @description
5165 * The `FormArray` bound to this directive.
5166 */
5167 get control() {
5168 return this.formDirective.getFormArray(this);
5169 }
5170 /**
5171 * @description
5172 * The top-level directive for this group if present, otherwise null.
5173 */
5174 get formDirective() {
5175 return this._parent ? this._parent.formDirective : null;
5176 }
5177 /**
5178 * @description
5179 * Returns an array that represents the path from the top-level form to this control.
5180 * Each index is the string name of the control on that level.
5181 */
5182 get path() {
5183 return controlPath(this.name == null ? this.name : this.name.toString(), this._parent);
5184 }
5185 _checkParentType() {
5186 if (_hasInvalidParent(this._parent) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
5187 throw arrayParentException();
5188 }
5189 }
5190 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormArrayName, deps: [{ token: ControlContainer, host: true, optional: true, skipSelf: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive }); }
5191 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: FormArrayName, selector: "[formArrayName]", inputs: { name: ["formArrayName", "name"] }, providers: [formArrayNameProvider], usesInheritance: true, ngImport: i0 }); }
5192}
5193i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormArrayName, decorators: [{
5194 type: Directive,
5195 args: [{ selector: '[formArrayName]', providers: [formArrayNameProvider] }]
5196 }], ctorParameters: () => [{ type: ControlContainer, decorators: [{
5197 type: Optional
5198 }, {
5199 type: Host
5200 }, {
5201 type: SkipSelf
5202 }] }, { type: undefined, decorators: [{
5203 type: Optional
5204 }, {
5205 type: Self
5206 }, {
5207 type: Inject,
5208 args: [NG_VALIDATORS]
5209 }] }, { type: undefined, decorators: [{
5210 type: Optional
5211 }, {
5212 type: Self
5213 }, {
5214 type: Inject,
5215 args: [NG_ASYNC_VALIDATORS]
5216 }] }], propDecorators: { name: [{
5217 type: Input,
5218 args: ['formArrayName']
5219 }] } });
5220function _hasInvalidParent(parent) {
5221 return !(parent instanceof FormGroupName) && !(parent instanceof FormGroupDirective) &&
5222 !(parent instanceof FormArrayName);
5223}
5224
5225const controlNameBinding = {
5226 provide: NgControl,
5227 useExisting: forwardRef(() => FormControlName)
5228};
5229/**
5230 * @description
5231 * Syncs a `FormControl` in an existing `FormGroup` to a form control
5232 * element by name.
5233 *
5234 * @see [Reactive Forms Guide](guide/reactive-forms)
5235 * @see {@link FormControl}
5236 * @see {@link AbstractControl}
5237 *
5238 * @usageNotes
5239 *
5240 * ### Register `FormControl` within a group
5241 *
5242 * The following example shows how to register multiple form controls within a form group
5243 * and set their value.
5244 *
5245 * {@example forms/ts/simpleFormGroup/simple_form_group_example.ts region='Component'}
5246 *
5247 * To see `formControlName` examples with different form control types, see:
5248 *
5249 * * Radio buttons: `RadioControlValueAccessor`
5250 * * Selects: `SelectControlValueAccessor`
5251 *
5252 * ### Use with ngModel is deprecated
5253 *
5254 * Support for using the `ngModel` input property and `ngModelChange` event with reactive
5255 * form directives has been deprecated in Angular v6 and is scheduled for removal in
5256 * a future version of Angular.
5257 *
5258 * For details, see [Deprecated features](guide/deprecations#ngmodel-with-reactive-forms).
5259 *
5260 * @ngModule ReactiveFormsModule
5261 * @publicApi
5262 */
5263class FormControlName extends NgControl {
5264 /**
5265 * @description
5266 * Triggers a warning in dev mode that this input should not be used with reactive forms.
5267 */
5268 set isDisabled(isDisabled) {
5269 if (typeof ngDevMode === 'undefined' || ngDevMode) {
5270 console.warn(disabledAttrWarning);
5271 }
5272 }
5273 /**
5274 * @description
5275 * Static property used to track whether any ngModel warnings have been sent across
5276 * all instances of FormControlName. Used to support warning config of "once".
5277 *
5278 * @internal
5279 */
5280 static { this._ngModelWarningSentOnce = false; }
5281 constructor(parent, validators, asyncValidators, valueAccessors, _ngModelWarningConfig) {
5282 super();
5283 this._ngModelWarningConfig = _ngModelWarningConfig;
5284 this._added = false;
5285 /**
5286 * @description
5287 * Tracks the name of the `FormControl` bound to the directive. The name corresponds
5288 * to a key in the parent `FormGroup` or `FormArray`.
5289 * Accepts a name as a string or a number.
5290 * The name in the form of a string is useful for individual forms,
5291 * while the numerical form allows for form controls to be bound
5292 * to indices when iterating over controls in a `FormArray`.
5293 */
5294 this.name = null;
5295 /** @deprecated as of v6 */
5296 this.update = new EventEmitter();
5297 /**
5298 * @description
5299 * Instance property used to track whether an ngModel warning has been sent out for this
5300 * particular FormControlName instance. Used to support warning config of "always".
5301 *
5302 * @internal
5303 */
5304 this._ngModelWarningSent = false;
5305 this._parent = parent;
5306 this._setValidators(validators);
5307 this._setAsyncValidators(asyncValidators);
5308 this.valueAccessor = selectValueAccessor(this, valueAccessors);
5309 }
5310 /** @nodoc */
5311 ngOnChanges(changes) {
5312 if (!this._added)
5313 this._setUpControl();
5314 if (isPropertyUpdated(changes, this.viewModel)) {
5315 if (typeof ngDevMode === 'undefined' || ngDevMode) {
5316 _ngModelWarning('formControlName', FormControlName, this, this._ngModelWarningConfig);
5317 }
5318 this.viewModel = this.model;
5319 this.formDirective.updateModel(this, this.model);
5320 }
5321 }
5322 /** @nodoc */
5323 ngOnDestroy() {
5324 if (this.formDirective) {
5325 this.formDirective.removeControl(this);
5326 }
5327 }
5328 /**
5329 * @description
5330 * Sets the new value for the view model and emits an `ngModelChange` event.
5331 *
5332 * @param newValue The new value for the view model.
5333 */
5334 viewToModelUpdate(newValue) {
5335 this.viewModel = newValue;
5336 this.update.emit(newValue);
5337 }
5338 /**
5339 * @description
5340 * Returns an array that represents the path from the top-level form to this control.
5341 * Each index is the string name of the control on that level.
5342 */
5343 get path() {
5344 return controlPath(this.name == null ? this.name : this.name.toString(), this._parent);
5345 }
5346 /**
5347 * @description
5348 * The top-level directive for this group if present, otherwise null.
5349 */
5350 get formDirective() {
5351 return this._parent ? this._parent.formDirective : null;
5352 }
5353 _checkParentType() {
5354 if (typeof ngDevMode === 'undefined' || ngDevMode) {
5355 if (!(this._parent instanceof FormGroupName) &&
5356 this._parent instanceof AbstractFormGroupDirective) {
5357 throw ngModelGroupException();
5358 }
5359 else if (!(this._parent instanceof FormGroupName) &&
5360 !(this._parent instanceof FormGroupDirective) &&
5361 !(this._parent instanceof FormArrayName)) {
5362 throw controlParentException();
5363 }
5364 }
5365 }
5366 _setUpControl() {
5367 this._checkParentType();
5368 this.control = this.formDirective.addControl(this);
5369 this._added = true;
5370 }
5371 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormControlName, deps: [{ token: ControlContainer, host: true, optional: true, skipSelf: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: NG_VALUE_ACCESSOR, optional: true, self: true }, { token: NG_MODEL_WITH_FORM_CONTROL_WARNING, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
5372 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: FormControlName, selector: "[formControlName]", inputs: { name: ["formControlName", "name"], isDisabled: ["disabled", "isDisabled"], model: ["ngModel", "model"] }, outputs: { update: "ngModelChange" }, providers: [controlNameBinding], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
5373}
5374i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormControlName, decorators: [{
5375 type: Directive,
5376 args: [{ selector: '[formControlName]', providers: [controlNameBinding] }]
5377 }], ctorParameters: () => [{ type: ControlContainer, decorators: [{
5378 type: Optional
5379 }, {
5380 type: Host
5381 }, {
5382 type: SkipSelf
5383 }] }, { type: undefined, decorators: [{
5384 type: Optional
5385 }, {
5386 type: Self
5387 }, {
5388 type: Inject,
5389 args: [NG_VALIDATORS]
5390 }] }, { type: undefined, decorators: [{
5391 type: Optional
5392 }, {
5393 type: Self
5394 }, {
5395 type: Inject,
5396 args: [NG_ASYNC_VALIDATORS]
5397 }] }, { type: undefined, decorators: [{
5398 type: Optional
5399 }, {
5400 type: Self
5401 }, {
5402 type: Inject,
5403 args: [NG_VALUE_ACCESSOR]
5404 }] }, { type: undefined, decorators: [{
5405 type: Optional
5406 }, {
5407 type: Inject,
5408 args: [NG_MODEL_WITH_FORM_CONTROL_WARNING]
5409 }] }], propDecorators: { name: [{
5410 type: Input,
5411 args: ['formControlName']
5412 }], isDisabled: [{
5413 type: Input,
5414 args: ['disabled']
5415 }], model: [{
5416 type: Input,
5417 args: ['ngModel']
5418 }], update: [{
5419 type: Output,
5420 args: ['ngModelChange']
5421 }] } });
5422
5423const SELECT_VALUE_ACCESSOR = {
5424 provide: NG_VALUE_ACCESSOR,
5425 useExisting: forwardRef(() => SelectControlValueAccessor),
5426 multi: true
5427};
5428function _buildValueString$1(id, value) {
5429 if (id == null)
5430 return `${value}`;
5431 if (value && typeof value === 'object')
5432 value = 'Object';
5433 return `${id}: ${value}`.slice(0, 50);
5434}
5435function _extractId$1(valueString) {
5436 return valueString.split(':')[0];
5437}
5438/**
5439 * @description
5440 * The `ControlValueAccessor` for writing select control values and listening to select control
5441 * changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
5442 * `NgModel` directives.
5443 *
5444 * @usageNotes
5445 *
5446 * ### Using select controls in a reactive form
5447 *
5448 * The following examples show how to use a select control in a reactive form.
5449 *
5450 * {@example forms/ts/reactiveSelectControl/reactive_select_control_example.ts region='Component'}
5451 *
5452 * ### Using select controls in a template-driven form
5453 *
5454 * To use a select in a template-driven form, simply add an `ngModel` and a `name`
5455 * attribute to the main `<select>` tag.
5456 *
5457 * {@example forms/ts/selectControl/select_control_example.ts region='Component'}
5458 *
5459 * ### Customizing option selection
5460 *
5461 * Angular uses object identity to select option. It's possible for the identities of items
5462 * to change while the data does not. This can happen, for example, if the items are produced
5463 * from an RPC to the server, and that RPC is re-run. Even if the data hasn't changed, the
5464 * second response will produce objects with different identities.
5465 *
5466 * To customize the default option comparison algorithm, `<select>` supports `compareWith` input.
5467 * `compareWith` takes a **function** which has two arguments: `option1` and `option2`.
5468 * If `compareWith` is given, Angular selects option by the return value of the function.
5469 *
5470 * ```ts
5471 * const selectedCountriesControl = new FormControl();
5472 * ```
5473 *
5474 * ```
5475 * <select [compareWith]="compareFn" [formControl]="selectedCountriesControl">
5476 * <option *ngFor="let country of countries" [ngValue]="country">
5477 * {{country.name}}
5478 * </option>
5479 * </select>
5480 *
5481 * compareFn(c1: Country, c2: Country): boolean {
5482 * return c1 && c2 ? c1.id === c2.id : c1 === c2;
5483 * }
5484 * ```
5485 *
5486 * **Note:** We listen to the 'change' event because 'input' events aren't fired
5487 * for selects in IE, see:
5488 * https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event#browser_compatibility
5489 *
5490 * @ngModule ReactiveFormsModule
5491 * @ngModule FormsModule
5492 * @publicApi
5493 */
5494class SelectControlValueAccessor extends BuiltInControlValueAccessor {
5495 constructor() {
5496 super(...arguments);
5497 /** @internal */
5498 this._optionMap = new Map();
5499 /** @internal */
5500 this._idCounter = 0;
5501 this._compareWith = Object.is;
5502 }
5503 /**
5504 * @description
5505 * Tracks the option comparison algorithm for tracking identities when
5506 * checking for changes.
5507 */
5508 set compareWith(fn) {
5509 if (typeof fn !== 'function' && (typeof ngDevMode === 'undefined' || ngDevMode)) {
5510 throw new ɵRuntimeError(1201 /* RuntimeErrorCode.COMPAREWITH_NOT_A_FN */, `compareWith must be a function, but received ${JSON.stringify(fn)}`);
5511 }
5512 this._compareWith = fn;
5513 }
5514 /**
5515 * Sets the "value" property on the select element.
5516 * @nodoc
5517 */
5518 writeValue(value) {
5519 this.value = value;
5520 const id = this._getOptionId(value);
5521 const valueString = _buildValueString$1(id, value);
5522 this.setProperty('value', valueString);
5523 }
5524 /**
5525 * Registers a function called when the control value changes.
5526 * @nodoc
5527 */
5528 registerOnChange(fn) {
5529 this.onChange = (valueString) => {
5530 this.value = this._getOptionValue(valueString);
5531 fn(this.value);
5532 };
5533 }
5534 /** @internal */
5535 _registerOption() {
5536 return (this._idCounter++).toString();
5537 }
5538 /** @internal */
5539 _getOptionId(value) {
5540 for (const id of this._optionMap.keys()) {
5541 if (this._compareWith(this._optionMap.get(id), value))
5542 return id;
5543 }
5544 return null;
5545 }
5546 /** @internal */
5547 _getOptionValue(valueString) {
5548 const id = _extractId$1(valueString);
5549 return this._optionMap.has(id) ? this._optionMap.get(id) : valueString;
5550 }
5551 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: SelectControlValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
5552 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: { compareWith: "compareWith" }, host: { listeners: { "change": "onChange($event.target.value)", "blur": "onTouched()" } }, providers: [SELECT_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 }); }
5553}
5554i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: SelectControlValueAccessor, decorators: [{
5555 type: Directive,
5556 args: [{
5557 selector: 'select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]',
5558 host: { '(change)': 'onChange($event.target.value)', '(blur)': 'onTouched()' },
5559 providers: [SELECT_VALUE_ACCESSOR]
5560 }]
5561 }], propDecorators: { compareWith: [{
5562 type: Input
5563 }] } });
5564/**
5565 * @description
5566 * Marks `<option>` as dynamic, so Angular can be notified when options change.
5567 *
5568 * @see {@link SelectControlValueAccessor}
5569 *
5570 * @ngModule ReactiveFormsModule
5571 * @ngModule FormsModule
5572 * @publicApi
5573 */
5574class NgSelectOption {
5575 constructor(_element, _renderer, _select) {
5576 this._element = _element;
5577 this._renderer = _renderer;
5578 this._select = _select;
5579 if (this._select)
5580 this.id = this._select._registerOption();
5581 }
5582 /**
5583 * @description
5584 * Tracks the value bound to the option element. Unlike the value binding,
5585 * ngValue supports binding to objects.
5586 */
5587 set ngValue(value) {
5588 if (this._select == null)
5589 return;
5590 this._select._optionMap.set(this.id, value);
5591 this._setElementValue(_buildValueString$1(this.id, value));
5592 this._select.writeValue(this._select.value);
5593 }
5594 /**
5595 * @description
5596 * Tracks simple string values bound to the option element.
5597 * For objects, use the `ngValue` input binding.
5598 */
5599 set value(value) {
5600 this._setElementValue(value);
5601 if (this._select)
5602 this._select.writeValue(this._select.value);
5603 }
5604 /** @internal */
5605 _setElementValue(value) {
5606 this._renderer.setProperty(this._element.nativeElement, 'value', value);
5607 }
5608 /** @nodoc */
5609 ngOnDestroy() {
5610 if (this._select) {
5611 this._select._optionMap.delete(this.id);
5612 this._select.writeValue(this._select.value);
5613 }
5614 }
5615 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NgSelectOption, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: SelectControlValueAccessor, host: true, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
5616 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: NgSelectOption, selector: "option", inputs: { ngValue: "ngValue", value: "value" }, ngImport: i0 }); }
5617}
5618i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NgSelectOption, decorators: [{
5619 type: Directive,
5620 args: [{ selector: 'option' }]
5621 }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: SelectControlValueAccessor, decorators: [{
5622 type: Optional
5623 }, {
5624 type: Host
5625 }] }], propDecorators: { ngValue: [{
5626 type: Input,
5627 args: ['ngValue']
5628 }], value: [{
5629 type: Input,
5630 args: ['value']
5631 }] } });
5632
5633const SELECT_MULTIPLE_VALUE_ACCESSOR = {
5634 provide: NG_VALUE_ACCESSOR,
5635 useExisting: forwardRef(() => SelectMultipleControlValueAccessor),
5636 multi: true
5637};
5638function _buildValueString(id, value) {
5639 if (id == null)
5640 return `${value}`;
5641 if (typeof value === 'string')
5642 value = `'${value}'`;
5643 if (value && typeof value === 'object')
5644 value = 'Object';
5645 return `${id}: ${value}`.slice(0, 50);
5646}
5647function _extractId(valueString) {
5648 return valueString.split(':')[0];
5649}
5650/** Mock interface for HTMLCollection */
5651class HTMLCollection {
5652}
5653/**
5654 * @description
5655 * The `ControlValueAccessor` for writing multi-select control values and listening to multi-select
5656 * control changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
5657 * `NgModel` directives.
5658 *
5659 * @see {@link SelectControlValueAccessor}
5660 *
5661 * @usageNotes
5662 *
5663 * ### Using a multi-select control
5664 *
5665 * The follow example shows you how to use a multi-select control with a reactive form.
5666 *
5667 * ```ts
5668 * const countryControl = new FormControl();
5669 * ```
5670 *
5671 * ```
5672 * <select multiple name="countries" [formControl]="countryControl">
5673 * <option *ngFor="let country of countries" [ngValue]="country">
5674 * {{ country.name }}
5675 * </option>
5676 * </select>
5677 * ```
5678 *
5679 * ### Customizing option selection
5680 *
5681 * To customize the default option comparison algorithm, `<select>` supports `compareWith` input.
5682 * See the `SelectControlValueAccessor` for usage.
5683 *
5684 * @ngModule ReactiveFormsModule
5685 * @ngModule FormsModule
5686 * @publicApi
5687 */
5688class SelectMultipleControlValueAccessor extends BuiltInControlValueAccessor {
5689 constructor() {
5690 super(...arguments);
5691 /** @internal */
5692 this._optionMap = new Map();
5693 /** @internal */
5694 this._idCounter = 0;
5695 this._compareWith = Object.is;
5696 }
5697 /**
5698 * @description
5699 * Tracks the option comparison algorithm for tracking identities when
5700 * checking for changes.
5701 */
5702 set compareWith(fn) {
5703 if (typeof fn !== 'function' && (typeof ngDevMode === 'undefined' || ngDevMode)) {
5704 throw new ɵRuntimeError(1201 /* RuntimeErrorCode.COMPAREWITH_NOT_A_FN */, `compareWith must be a function, but received ${JSON.stringify(fn)}`);
5705 }
5706 this._compareWith = fn;
5707 }
5708 /**
5709 * Sets the "value" property on one or of more of the select's options.
5710 * @nodoc
5711 */
5712 writeValue(value) {
5713 this.value = value;
5714 let optionSelectedStateSetter;
5715 if (Array.isArray(value)) {
5716 // convert values to ids
5717 const ids = value.map((v) => this._getOptionId(v));
5718 optionSelectedStateSetter = (opt, o) => {
5719 opt._setSelected(ids.indexOf(o.toString()) > -1);
5720 };
5721 }
5722 else {
5723 optionSelectedStateSetter = (opt, o) => {
5724 opt._setSelected(false);
5725 };
5726 }
5727 this._optionMap.forEach(optionSelectedStateSetter);
5728 }
5729 /**
5730 * Registers a function called when the control value changes
5731 * and writes an array of the selected options.
5732 * @nodoc
5733 */
5734 registerOnChange(fn) {
5735 this.onChange = (element) => {
5736 const selected = [];
5737 const selectedOptions = element.selectedOptions;
5738 if (selectedOptions !== undefined) {
5739 const options = selectedOptions;
5740 for (let i = 0; i < options.length; i++) {
5741 const opt = options[i];
5742 const val = this._getOptionValue(opt.value);
5743 selected.push(val);
5744 }
5745 }
5746 // Degrade to use `options` when `selectedOptions` property is not available.
5747 // Note: the `selectedOptions` is available in all supported browsers, but the Domino lib
5748 // doesn't have it currently, see https://github.com/fgnass/domino/issues/177.
5749 else {
5750 const options = element.options;
5751 for (let i = 0; i < options.length; i++) {
5752 const opt = options[i];
5753 if (opt.selected) {
5754 const val = this._getOptionValue(opt.value);
5755 selected.push(val);
5756 }
5757 }
5758 }
5759 this.value = selected;
5760 fn(selected);
5761 };
5762 }
5763 /** @internal */
5764 _registerOption(value) {
5765 const id = (this._idCounter++).toString();
5766 this._optionMap.set(id, value);
5767 return id;
5768 }
5769 /** @internal */
5770 _getOptionId(value) {
5771 for (const id of this._optionMap.keys()) {
5772 if (this._compareWith(this._optionMap.get(id)._value, value))
5773 return id;
5774 }
5775 return null;
5776 }
5777 /** @internal */
5778 _getOptionValue(valueString) {
5779 const id = _extractId(valueString);
5780 return this._optionMap.has(id) ? this._optionMap.get(id)._value : valueString;
5781 }
5782 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: SelectMultipleControlValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
5783 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: SelectMultipleControlValueAccessor, selector: "select[multiple][formControlName],select[multiple][formControl],select[multiple][ngModel]", inputs: { compareWith: "compareWith" }, host: { listeners: { "change": "onChange($event.target)", "blur": "onTouched()" } }, providers: [SELECT_MULTIPLE_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 }); }
5784}
5785i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: SelectMultipleControlValueAccessor, decorators: [{
5786 type: Directive,
5787 args: [{
5788 selector: 'select[multiple][formControlName],select[multiple][formControl],select[multiple][ngModel]',
5789 host: { '(change)': 'onChange($event.target)', '(blur)': 'onTouched()' },
5790 providers: [SELECT_MULTIPLE_VALUE_ACCESSOR]
5791 }]
5792 }], propDecorators: { compareWith: [{
5793 type: Input
5794 }] } });
5795/**
5796 * @description
5797 * Marks `<option>` as dynamic, so Angular can be notified when options change.
5798 *
5799 * @see {@link SelectMultipleControlValueAccessor}
5800 *
5801 * @ngModule ReactiveFormsModule
5802 * @ngModule FormsModule
5803 * @publicApi
5804 */
5805class ɵNgSelectMultipleOption {
5806 constructor(_element, _renderer, _select) {
5807 this._element = _element;
5808 this._renderer = _renderer;
5809 this._select = _select;
5810 if (this._select) {
5811 this.id = this._select._registerOption(this);
5812 }
5813 }
5814 /**
5815 * @description
5816 * Tracks the value bound to the option element. Unlike the value binding,
5817 * ngValue supports binding to objects.
5818 */
5819 set ngValue(value) {
5820 if (this._select == null)
5821 return;
5822 this._value = value;
5823 this._setElementValue(_buildValueString(this.id, value));
5824 this._select.writeValue(this._select.value);
5825 }
5826 /**
5827 * @description
5828 * Tracks simple string values bound to the option element.
5829 * For objects, use the `ngValue` input binding.
5830 */
5831 set value(value) {
5832 if (this._select) {
5833 this._value = value;
5834 this._setElementValue(_buildValueString(this.id, value));
5835 this._select.writeValue(this._select.value);
5836 }
5837 else {
5838 this._setElementValue(value);
5839 }
5840 }
5841 /** @internal */
5842 _setElementValue(value) {
5843 this._renderer.setProperty(this._element.nativeElement, 'value', value);
5844 }
5845 /** @internal */
5846 _setSelected(selected) {
5847 this._renderer.setProperty(this._element.nativeElement, 'selected', selected);
5848 }
5849 /** @nodoc */
5850 ngOnDestroy() {
5851 if (this._select) {
5852 this._select._optionMap.delete(this.id);
5853 this._select.writeValue(this._select.value);
5854 }
5855 }
5856 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ɵNgSelectMultipleOption, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: SelectMultipleControlValueAccessor, host: true, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
5857 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: ɵNgSelectMultipleOption, selector: "option", inputs: { ngValue: "ngValue", value: "value" }, ngImport: i0 }); }
5858}
5859i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ɵNgSelectMultipleOption, decorators: [{
5860 type: Directive,
5861 args: [{ selector: 'option' }]
5862 }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: SelectMultipleControlValueAccessor, decorators: [{
5863 type: Optional
5864 }, {
5865 type: Host
5866 }] }], propDecorators: { ngValue: [{
5867 type: Input,
5868 args: ['ngValue']
5869 }], value: [{
5870 type: Input,
5871 args: ['value']
5872 }] } });
5873
5874/**
5875 * Method that updates string to integer if not already a number
5876 *
5877 * @param value The value to convert to integer.
5878 * @returns value of parameter converted to number or integer.
5879 */
5880function toInteger(value) {
5881 return typeof value === 'number' ? value : parseInt(value, 10);
5882}
5883/**
5884 * Method that ensures that provided value is a float (and converts it to float if needed).
5885 *
5886 * @param value The value to convert to float.
5887 * @returns value of parameter converted to number or float.
5888 */
5889function toFloat(value) {
5890 return typeof value === 'number' ? value : parseFloat(value);
5891}
5892/**
5893 * A base class for Validator-based Directives. The class contains common logic shared across such
5894 * Directives.
5895 *
5896 * For internal use only, this class is not intended for use outside of the Forms package.
5897 */
5898class AbstractValidatorDirective {
5899 constructor() {
5900 this._validator = nullValidator;
5901 }
5902 /** @nodoc */
5903 ngOnChanges(changes) {
5904 if (this.inputName in changes) {
5905 const input = this.normalizeInput(changes[this.inputName].currentValue);
5906 this._enabled = this.enabled(input);
5907 this._validator = this._enabled ? this.createValidator(input) : nullValidator;
5908 if (this._onChange) {
5909 this._onChange();
5910 }
5911 }
5912 }
5913 /** @nodoc */
5914 validate(control) {
5915 return this._validator(control);
5916 }
5917 /** @nodoc */
5918 registerOnValidatorChange(fn) {
5919 this._onChange = fn;
5920 }
5921 /**
5922 * @description
5923 * Determines whether this validator should be active or not based on an input.
5924 * Base class implementation checks whether an input is defined (if the value is different from
5925 * `null` and `undefined`). Validator classes that extend this base class can override this
5926 * function with the logic specific to a particular validator directive.
5927 */
5928 enabled(input) {
5929 return input != null /* both `null` and `undefined` */;
5930 }
5931 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: AbstractValidatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
5932 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: AbstractValidatorDirective, usesOnChanges: true, ngImport: i0 }); }
5933}
5934i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: AbstractValidatorDirective, decorators: [{
5935 type: Directive
5936 }] });
5937/**
5938 * @description
5939 * Provider which adds `MaxValidator` to the `NG_VALIDATORS` multi-provider list.
5940 */
5941const MAX_VALIDATOR = {
5942 provide: NG_VALIDATORS,
5943 useExisting: forwardRef(() => MaxValidator),
5944 multi: true
5945};
5946/**
5947 * A directive which installs the {@link MaxValidator} for any `formControlName`,
5948 * `formControl`, or control with `ngModel` that also has a `max` attribute.
5949 *
5950 * @see [Form Validation](guide/form-validation)
5951 *
5952 * @usageNotes
5953 *
5954 * ### Adding a max validator
5955 *
5956 * The following example shows how to add a max validator to an input attached to an
5957 * ngModel binding.
5958 *
5959 * ```html
5960 * <input type="number" ngModel max="4">
5961 * ```
5962 *
5963 * @ngModule ReactiveFormsModule
5964 * @ngModule FormsModule
5965 * @publicApi
5966 */
5967class MaxValidator extends AbstractValidatorDirective {
5968 constructor() {
5969 super(...arguments);
5970 /** @internal */
5971 this.inputName = 'max';
5972 /** @internal */
5973 this.normalizeInput = (input) => toFloat(input);
5974 /** @internal */
5975 this.createValidator = (max) => maxValidator(max);
5976 }
5977 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: MaxValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
5978 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: { max: "max" }, host: { properties: { "attr.max": "_enabled ? max : null" } }, providers: [MAX_VALIDATOR], usesInheritance: true, ngImport: i0 }); }
5979}
5980i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: MaxValidator, decorators: [{
5981 type: Directive,
5982 args: [{
5983 selector: 'input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]',
5984 providers: [MAX_VALIDATOR],
5985 host: { '[attr.max]': '_enabled ? max : null' }
5986 }]
5987 }], propDecorators: { max: [{
5988 type: Input
5989 }] } });
5990/**
5991 * @description
5992 * Provider which adds `MinValidator` to the `NG_VALIDATORS` multi-provider list.
5993 */
5994const MIN_VALIDATOR = {
5995 provide: NG_VALIDATORS,
5996 useExisting: forwardRef(() => MinValidator),
5997 multi: true
5998};
5999/**
6000 * A directive which installs the {@link MinValidator} for any `formControlName`,
6001 * `formControl`, or control with `ngModel` that also has a `min` attribute.
6002 *
6003 * @see [Form Validation](guide/form-validation)
6004 *
6005 * @usageNotes
6006 *
6007 * ### Adding a min validator
6008 *
6009 * The following example shows how to add a min validator to an input attached to an
6010 * ngModel binding.
6011 *
6012 * ```html
6013 * <input type="number" ngModel min="4">
6014 * ```
6015 *
6016 * @ngModule ReactiveFormsModule
6017 * @ngModule FormsModule
6018 * @publicApi
6019 */
6020class MinValidator extends AbstractValidatorDirective {
6021 constructor() {
6022 super(...arguments);
6023 /** @internal */
6024 this.inputName = 'min';
6025 /** @internal */
6026 this.normalizeInput = (input) => toFloat(input);
6027 /** @internal */
6028 this.createValidator = (min) => minValidator(min);
6029 }
6030 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: MinValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
6031 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: { min: "min" }, host: { properties: { "attr.min": "_enabled ? min : null" } }, providers: [MIN_VALIDATOR], usesInheritance: true, ngImport: i0 }); }
6032}
6033i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: MinValidator, decorators: [{
6034 type: Directive,
6035 args: [{
6036 selector: 'input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]',
6037 providers: [MIN_VALIDATOR],
6038 host: { '[attr.min]': '_enabled ? min : null' }
6039 }]
6040 }], propDecorators: { min: [{
6041 type: Input
6042 }] } });
6043/**
6044 * @description
6045 * Provider which adds `RequiredValidator` to the `NG_VALIDATORS` multi-provider list.
6046 */
6047const REQUIRED_VALIDATOR = {
6048 provide: NG_VALIDATORS,
6049 useExisting: forwardRef(() => RequiredValidator),
6050 multi: true
6051};
6052/**
6053 * @description
6054 * Provider which adds `CheckboxRequiredValidator` to the `NG_VALIDATORS` multi-provider list.
6055 */
6056const CHECKBOX_REQUIRED_VALIDATOR = {
6057 provide: NG_VALIDATORS,
6058 useExisting: forwardRef(() => CheckboxRequiredValidator),
6059 multi: true
6060};
6061/**
6062 * @description
6063 * A directive that adds the `required` validator to any controls marked with the
6064 * `required` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
6065 *
6066 * @see [Form Validation](guide/form-validation)
6067 *
6068 * @usageNotes
6069 *
6070 * ### Adding a required validator using template-driven forms
6071 *
6072 * ```
6073 * <input name="fullName" ngModel required>
6074 * ```
6075 *
6076 * @ngModule FormsModule
6077 * @ngModule ReactiveFormsModule
6078 * @publicApi
6079 */
6080class RequiredValidator extends AbstractValidatorDirective {
6081 constructor() {
6082 super(...arguments);
6083 /** @internal */
6084 this.inputName = 'required';
6085 /** @internal */
6086 this.normalizeInput = booleanAttribute;
6087 /** @internal */
6088 this.createValidator = (input) => requiredValidator;
6089 }
6090 /** @nodoc */
6091 enabled(input) {
6092 return input;
6093 }
6094 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: RequiredValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
6095 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: { required: "required" }, host: { properties: { "attr.required": "_enabled ? \"\" : null" } }, providers: [REQUIRED_VALIDATOR], usesInheritance: true, ngImport: i0 }); }
6096}
6097i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: RequiredValidator, decorators: [{
6098 type: Directive,
6099 args: [{
6100 selector: ':not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]',
6101 providers: [REQUIRED_VALIDATOR],
6102 host: { '[attr.required]': '_enabled ? "" : null' }
6103 }]
6104 }], propDecorators: { required: [{
6105 type: Input
6106 }] } });
6107/**
6108 * A Directive that adds the `required` validator to checkbox controls marked with the
6109 * `required` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
6110 *
6111 * @see [Form Validation](guide/form-validation)
6112 *
6113 * @usageNotes
6114 *
6115 * ### Adding a required checkbox validator using template-driven forms
6116 *
6117 * The following example shows how to add a checkbox required validator to an input attached to an
6118 * ngModel binding.
6119 *
6120 * ```
6121 * <input type="checkbox" name="active" ngModel required>
6122 * ```
6123 *
6124 * @publicApi
6125 * @ngModule FormsModule
6126 * @ngModule ReactiveFormsModule
6127 */
6128class CheckboxRequiredValidator extends RequiredValidator {
6129 constructor() {
6130 super(...arguments);
6131 /** @internal */
6132 this.createValidator = (input) => requiredTrueValidator;
6133 }
6134 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: CheckboxRequiredValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
6135 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: CheckboxRequiredValidator, selector: "input[type=checkbox][required][formControlName],input[type=checkbox][required][formControl],input[type=checkbox][required][ngModel]", host: { properties: { "attr.required": "_enabled ? \"\" : null" } }, providers: [CHECKBOX_REQUIRED_VALIDATOR], usesInheritance: true, ngImport: i0 }); }
6136}
6137i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: CheckboxRequiredValidator, decorators: [{
6138 type: Directive,
6139 args: [{
6140 selector: 'input[type=checkbox][required][formControlName],input[type=checkbox][required][formControl],input[type=checkbox][required][ngModel]',
6141 providers: [CHECKBOX_REQUIRED_VALIDATOR],
6142 host: { '[attr.required]': '_enabled ? "" : null' }
6143 }]
6144 }] });
6145/**
6146 * @description
6147 * Provider which adds `EmailValidator` to the `NG_VALIDATORS` multi-provider list.
6148 */
6149const EMAIL_VALIDATOR = {
6150 provide: NG_VALIDATORS,
6151 useExisting: forwardRef(() => EmailValidator),
6152 multi: true
6153};
6154/**
6155 * A directive that adds the `email` validator to controls marked with the
6156 * `email` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
6157 *
6158 * The email validation is based on the WHATWG HTML specification with some enhancements to
6159 * incorporate more RFC rules. More information can be found on the [Validators.email
6160 * page](api/forms/Validators#email).
6161 *
6162 * @see [Form Validation](guide/form-validation)
6163 *
6164 * @usageNotes
6165 *
6166 * ### Adding an email validator
6167 *
6168 * The following example shows how to add an email validator to an input attached to an ngModel
6169 * binding.
6170 *
6171 * ```
6172 * <input type="email" name="email" ngModel email>
6173 * <input type="email" name="email" ngModel email="true">
6174 * <input type="email" name="email" ngModel [email]="true">
6175 * ```
6176 *
6177 * @publicApi
6178 * @ngModule FormsModule
6179 * @ngModule ReactiveFormsModule
6180 */
6181class EmailValidator extends AbstractValidatorDirective {
6182 constructor() {
6183 super(...arguments);
6184 /** @internal */
6185 this.inputName = 'email';
6186 /** @internal */
6187 this.normalizeInput = booleanAttribute;
6188 /** @internal */
6189 this.createValidator = (input) => emailValidator;
6190 }
6191 /** @nodoc */
6192 enabled(input) {
6193 return input;
6194 }
6195 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: EmailValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
6196 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: { email: "email" }, providers: [EMAIL_VALIDATOR], usesInheritance: true, ngImport: i0 }); }
6197}
6198i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: EmailValidator, decorators: [{
6199 type: Directive,
6200 args: [{
6201 selector: '[email][formControlName],[email][formControl],[email][ngModel]',
6202 providers: [EMAIL_VALIDATOR]
6203 }]
6204 }], propDecorators: { email: [{
6205 type: Input
6206 }] } });
6207/**
6208 * @description
6209 * Provider which adds `MinLengthValidator` to the `NG_VALIDATORS` multi-provider list.
6210 */
6211const MIN_LENGTH_VALIDATOR = {
6212 provide: NG_VALIDATORS,
6213 useExisting: forwardRef(() => MinLengthValidator),
6214 multi: true
6215};
6216/**
6217 * A directive that adds minimum length validation to controls marked with the
6218 * `minlength` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
6219 *
6220 * @see [Form Validation](guide/form-validation)
6221 *
6222 * @usageNotes
6223 *
6224 * ### Adding a minimum length validator
6225 *
6226 * The following example shows how to add a minimum length validator to an input attached to an
6227 * ngModel binding.
6228 *
6229 * ```html
6230 * <input name="firstName" ngModel minlength="4">
6231 * ```
6232 *
6233 * @ngModule ReactiveFormsModule
6234 * @ngModule FormsModule
6235 * @publicApi
6236 */
6237class MinLengthValidator extends AbstractValidatorDirective {
6238 constructor() {
6239 super(...arguments);
6240 /** @internal */
6241 this.inputName = 'minlength';
6242 /** @internal */
6243 this.normalizeInput = (input) => toInteger(input);
6244 /** @internal */
6245 this.createValidator = (minlength) => minLengthValidator(minlength);
6246 }
6247 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: MinLengthValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
6248 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: { minlength: "minlength" }, host: { properties: { "attr.minlength": "_enabled ? minlength : null" } }, providers: [MIN_LENGTH_VALIDATOR], usesInheritance: true, ngImport: i0 }); }
6249}
6250i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: MinLengthValidator, decorators: [{
6251 type: Directive,
6252 args: [{
6253 selector: '[minlength][formControlName],[minlength][formControl],[minlength][ngModel]',
6254 providers: [MIN_LENGTH_VALIDATOR],
6255 host: { '[attr.minlength]': '_enabled ? minlength : null' }
6256 }]
6257 }], propDecorators: { minlength: [{
6258 type: Input
6259 }] } });
6260/**
6261 * @description
6262 * Provider which adds `MaxLengthValidator` to the `NG_VALIDATORS` multi-provider list.
6263 */
6264const MAX_LENGTH_VALIDATOR = {
6265 provide: NG_VALIDATORS,
6266 useExisting: forwardRef(() => MaxLengthValidator),
6267 multi: true
6268};
6269/**
6270 * A directive that adds maximum length validation to controls marked with the
6271 * `maxlength` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
6272 *
6273 * @see [Form Validation](guide/form-validation)
6274 *
6275 * @usageNotes
6276 *
6277 * ### Adding a maximum length validator
6278 *
6279 * The following example shows how to add a maximum length validator to an input attached to an
6280 * ngModel binding.
6281 *
6282 * ```html
6283 * <input name="firstName" ngModel maxlength="25">
6284 * ```
6285 *
6286 * @ngModule ReactiveFormsModule
6287 * @ngModule FormsModule
6288 * @publicApi
6289 */
6290class MaxLengthValidator extends AbstractValidatorDirective {
6291 constructor() {
6292 super(...arguments);
6293 /** @internal */
6294 this.inputName = 'maxlength';
6295 /** @internal */
6296 this.normalizeInput = (input) => toInteger(input);
6297 /** @internal */
6298 this.createValidator = (maxlength) => maxLengthValidator(maxlength);
6299 }
6300 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: MaxLengthValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
6301 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: { maxlength: "maxlength" }, host: { properties: { "attr.maxlength": "_enabled ? maxlength : null" } }, providers: [MAX_LENGTH_VALIDATOR], usesInheritance: true, ngImport: i0 }); }
6302}
6303i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: MaxLengthValidator, decorators: [{
6304 type: Directive,
6305 args: [{
6306 selector: '[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]',
6307 providers: [MAX_LENGTH_VALIDATOR],
6308 host: { '[attr.maxlength]': '_enabled ? maxlength : null' }
6309 }]
6310 }], propDecorators: { maxlength: [{
6311 type: Input
6312 }] } });
6313/**
6314 * @description
6315 * Provider which adds `PatternValidator` to the `NG_VALIDATORS` multi-provider list.
6316 */
6317const PATTERN_VALIDATOR = {
6318 provide: NG_VALIDATORS,
6319 useExisting: forwardRef(() => PatternValidator),
6320 multi: true
6321};
6322/**
6323 * @description
6324 * A directive that adds regex pattern validation to controls marked with the
6325 * `pattern` attribute. The regex must match the entire control value.
6326 * The directive is provided with the `NG_VALIDATORS` multi-provider list.
6327 *
6328 * @see [Form Validation](guide/form-validation)
6329 *
6330 * @usageNotes
6331 *
6332 * ### Adding a pattern validator
6333 *
6334 * The following example shows how to add a pattern validator to an input attached to an
6335 * ngModel binding.
6336 *
6337 * ```html
6338 * <input name="firstName" ngModel pattern="[a-zA-Z ]*">
6339 * ```
6340 *
6341 * @ngModule ReactiveFormsModule
6342 * @ngModule FormsModule
6343 * @publicApi
6344 */
6345class PatternValidator extends AbstractValidatorDirective {
6346 constructor() {
6347 super(...arguments);
6348 /** @internal */
6349 this.inputName = 'pattern';
6350 /** @internal */
6351 this.normalizeInput = (input) => input;
6352 /** @internal */
6353 this.createValidator = (input) => patternValidator(input);
6354 }
6355 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: PatternValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
6356 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.5", type: PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: { pattern: "pattern" }, host: { properties: { "attr.pattern": "_enabled ? pattern : null" } }, providers: [PATTERN_VALIDATOR], usesInheritance: true, ngImport: i0 }); }
6357}
6358i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: PatternValidator, decorators: [{
6359 type: Directive,
6360 args: [{
6361 selector: '[pattern][formControlName],[pattern][formControl],[pattern][ngModel]',
6362 providers: [PATTERN_VALIDATOR],
6363 host: { '[attr.pattern]': '_enabled ? pattern : null' }
6364 }]
6365 }], propDecorators: { pattern: [{
6366 type: Input
6367 }] } });
6368
6369const SHARED_FORM_DIRECTIVES = [
6370 ɵNgNoValidate,
6371 NgSelectOption,
6372 ɵNgSelectMultipleOption,
6373 DefaultValueAccessor,
6374 NumberValueAccessor,
6375 RangeValueAccessor,
6376 CheckboxControlValueAccessor,
6377 SelectControlValueAccessor,
6378 SelectMultipleControlValueAccessor,
6379 RadioControlValueAccessor,
6380 NgControlStatus,
6381 NgControlStatusGroup,
6382 RequiredValidator,
6383 MinLengthValidator,
6384 MaxLengthValidator,
6385 PatternValidator,
6386 CheckboxRequiredValidator,
6387 EmailValidator,
6388 MinValidator,
6389 MaxValidator,
6390];
6391const TEMPLATE_DRIVEN_DIRECTIVES = [NgModel, NgModelGroup, NgForm];
6392const REACTIVE_DRIVEN_DIRECTIVES = [FormControlDirective, FormGroupDirective, FormControlName, FormGroupName, FormArrayName];
6393/**
6394 * Internal module used for sharing directives between FormsModule and ReactiveFormsModule
6395 */
6396class ɵInternalFormsSharedModule {
6397 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ɵInternalFormsSharedModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
6398 static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.5", ngImport: i0, type: ɵInternalFormsSharedModule, declarations: [ɵNgNoValidate,
6399 NgSelectOption,
6400 ɵNgSelectMultipleOption,
6401 DefaultValueAccessor,
6402 NumberValueAccessor,
6403 RangeValueAccessor,
6404 CheckboxControlValueAccessor,
6405 SelectControlValueAccessor,
6406 SelectMultipleControlValueAccessor,
6407 RadioControlValueAccessor,
6408 NgControlStatus,
6409 NgControlStatusGroup,
6410 RequiredValidator,
6411 MinLengthValidator,
6412 MaxLengthValidator,
6413 PatternValidator,
6414 CheckboxRequiredValidator,
6415 EmailValidator,
6416 MinValidator,
6417 MaxValidator], exports: [ɵNgNoValidate,
6418 NgSelectOption,
6419 ɵNgSelectMultipleOption,
6420 DefaultValueAccessor,
6421 NumberValueAccessor,
6422 RangeValueAccessor,
6423 CheckboxControlValueAccessor,
6424 SelectControlValueAccessor,
6425 SelectMultipleControlValueAccessor,
6426 RadioControlValueAccessor,
6427 NgControlStatus,
6428 NgControlStatusGroup,
6429 RequiredValidator,
6430 MinLengthValidator,
6431 MaxLengthValidator,
6432 PatternValidator,
6433 CheckboxRequiredValidator,
6434 EmailValidator,
6435 MinValidator,
6436 MaxValidator] }); }
6437 static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ɵInternalFormsSharedModule }); }
6438}
6439i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ɵInternalFormsSharedModule, decorators: [{
6440 type: NgModule,
6441 args: [{
6442 declarations: SHARED_FORM_DIRECTIVES,
6443 exports: SHARED_FORM_DIRECTIVES,
6444 }]
6445 }] });
6446
6447/**
6448 * Tracks the value and validity state of an array of `FormControl`,
6449 * `FormGroup` or `FormArray` instances.
6450 *
6451 * A `FormArray` aggregates the values of each child `FormControl` into an array.
6452 * It calculates its status by reducing the status values of its children. For example, if one of
6453 * the controls in a `FormArray` is invalid, the entire array becomes invalid.
6454 *
6455 * `FormArray` accepts one generic argument, which is the type of the controls inside.
6456 * If you need a heterogenous array, use {@link UntypedFormArray}.
6457 *
6458 * `FormArray` is one of the four fundamental building blocks used to define forms in Angular,
6459 * along with `FormControl`, `FormGroup`, and `FormRecord`.
6460 *
6461 * @usageNotes
6462 *
6463 * ### Create an array of form controls
6464 *
6465 * ```
6466 * const arr = new FormArray([
6467 * new FormControl('Nancy', Validators.minLength(2)),
6468 * new FormControl('Drew'),
6469 * ]);
6470 *
6471 * console.log(arr.value); // ['Nancy', 'Drew']
6472 * console.log(arr.status); // 'VALID'
6473 * ```
6474 *
6475 * ### Create a form array with array-level validators
6476 *
6477 * You include array-level validators and async validators. These come in handy
6478 * when you want to perform validation that considers the value of more than one child
6479 * control.
6480 *
6481 * The two types of validators are passed in separately as the second and third arg
6482 * respectively, or together as part of an options object.
6483 *
6484 * ```
6485 * const arr = new FormArray([
6486 * new FormControl('Nancy'),
6487 * new FormControl('Drew')
6488 * ], {validators: myValidator, asyncValidators: myAsyncValidator});
6489 * ```
6490 *
6491 * ### Set the updateOn property for all controls in a form array
6492 *
6493 * The options object is used to set a default value for each child
6494 * control's `updateOn` property. If you set `updateOn` to `'blur'` at the
6495 * array level, all child controls default to 'blur', unless the child
6496 * has explicitly specified a different `updateOn` value.
6497 *
6498 * ```ts
6499 * const arr = new FormArray([
6500 * new FormControl()
6501 * ], {updateOn: 'blur'});
6502 * ```
6503 *
6504 * ### Adding or removing controls from a form array
6505 *
6506 * To change the controls in the array, use the `push`, `insert`, `removeAt` or `clear` methods
6507 * in `FormArray` itself. These methods ensure the controls are properly tracked in the
6508 * form's hierarchy. Do not modify the array of `AbstractControl`s used to instantiate
6509 * the `FormArray` directly, as that result in strange and unexpected behavior such
6510 * as broken change detection.
6511 *
6512 * @publicApi
6513 */
6514class FormArray extends AbstractControl {
6515 /**
6516 * Creates a new `FormArray` instance.
6517 *
6518 * @param controls An array of child controls. Each child control is given an index
6519 * where it is registered.
6520 *
6521 * @param validatorOrOpts A synchronous validator function, or an array of
6522 * such functions, or an `AbstractControlOptions` object that contains validation functions
6523 * and a validation trigger.
6524 *
6525 * @param asyncValidator A single async validator or array of async validator functions
6526 *
6527 */
6528 constructor(controls, validatorOrOpts, asyncValidator) {
6529 super(pickValidators(validatorOrOpts), pickAsyncValidators(asyncValidator, validatorOrOpts));
6530 this.controls = controls;
6531 this._initObservables();
6532 this._setUpdateStrategy(validatorOrOpts);
6533 this._setUpControls();
6534 this.updateValueAndValidity({
6535 onlySelf: true,
6536 // If `asyncValidator` is present, it will trigger control status change from `PENDING` to
6537 // `VALID` or `INVALID`.
6538 // The status should be broadcasted via the `statusChanges` observable, so we set `emitEvent`
6539 // to `true` to allow that during the control creation process.
6540 emitEvent: !!this.asyncValidator
6541 });
6542 }
6543 /**
6544 * Get the `AbstractControl` at the given `index` in the array.
6545 *
6546 * @param index Index in the array to retrieve the control. If `index` is negative, it will wrap
6547 * around from the back, and if index is greatly negative (less than `-length`), the result is
6548 * undefined. This behavior is the same as `Array.at(index)`.
6549 */
6550 at(index) {
6551 return this.controls[this._adjustIndex(index)];
6552 }
6553 /**
6554 * Insert a new `AbstractControl` at the end of the array.
6555 *
6556 * @param control Form control to be inserted
6557 * @param options Specifies whether this FormArray instance should emit events after a new
6558 * control is added.
6559 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
6560 * `valueChanges` observables emit events with the latest status and value when the control is
6561 * inserted. When false, no events are emitted.
6562 */
6563 push(control, options = {}) {
6564 this.controls.push(control);
6565 this._registerControl(control);
6566 this.updateValueAndValidity({ emitEvent: options.emitEvent });
6567 this._onCollectionChange();
6568 }
6569 /**
6570 * Insert a new `AbstractControl` at the given `index` in the array.
6571 *
6572 * @param index Index in the array to insert the control. If `index` is negative, wraps around
6573 * from the back. If `index` is greatly negative (less than `-length`), prepends to the array.
6574 * This behavior is the same as `Array.splice(index, 0, control)`.
6575 * @param control Form control to be inserted
6576 * @param options Specifies whether this FormArray instance should emit events after a new
6577 * control is inserted.
6578 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
6579 * `valueChanges` observables emit events with the latest status and value when the control is
6580 * inserted. When false, no events are emitted.
6581 */
6582 insert(index, control, options = {}) {
6583 this.controls.splice(index, 0, control);
6584 this._registerControl(control);
6585 this.updateValueAndValidity({ emitEvent: options.emitEvent });
6586 }
6587 /**
6588 * Remove the control at the given `index` in the array.
6589 *
6590 * @param index Index in the array to remove the control. If `index` is negative, wraps around
6591 * from the back. If `index` is greatly negative (less than `-length`), removes the first
6592 * element. This behavior is the same as `Array.splice(index, 1)`.
6593 * @param options Specifies whether this FormArray instance should emit events after a
6594 * control is removed.
6595 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
6596 * `valueChanges` observables emit events with the latest status and value when the control is
6597 * removed. When false, no events are emitted.
6598 */
6599 removeAt(index, options = {}) {
6600 // Adjust the index, then clamp it at no less than 0 to prevent undesired underflows.
6601 let adjustedIndex = this._adjustIndex(index);
6602 if (adjustedIndex < 0)
6603 adjustedIndex = 0;
6604 if (this.controls[adjustedIndex])
6605 this.controls[adjustedIndex]._registerOnCollectionChange(() => { });
6606 this.controls.splice(adjustedIndex, 1);
6607 this.updateValueAndValidity({ emitEvent: options.emitEvent });
6608 }
6609 /**
6610 * Replace an existing control.
6611 *
6612 * @param index Index in the array to replace the control. If `index` is negative, wraps around
6613 * from the back. If `index` is greatly negative (less than `-length`), replaces the first
6614 * element. This behavior is the same as `Array.splice(index, 1, control)`.
6615 * @param control The `AbstractControl` control to replace the existing control
6616 * @param options Specifies whether this FormArray instance should emit events after an
6617 * existing control is replaced with a new one.
6618 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
6619 * `valueChanges` observables emit events with the latest status and value when the control is
6620 * replaced with a new one. When false, no events are emitted.
6621 */
6622 setControl(index, control, options = {}) {
6623 // Adjust the index, then clamp it at no less than 0 to prevent undesired underflows.
6624 let adjustedIndex = this._adjustIndex(index);
6625 if (adjustedIndex < 0)
6626 adjustedIndex = 0;
6627 if (this.controls[adjustedIndex])
6628 this.controls[adjustedIndex]._registerOnCollectionChange(() => { });
6629 this.controls.splice(adjustedIndex, 1);
6630 if (control) {
6631 this.controls.splice(adjustedIndex, 0, control);
6632 this._registerControl(control);
6633 }
6634 this.updateValueAndValidity({ emitEvent: options.emitEvent });
6635 this._onCollectionChange();
6636 }
6637 /**
6638 * Length of the control array.
6639 */
6640 get length() {
6641 return this.controls.length;
6642 }
6643 /**
6644 * Sets the value of the `FormArray`. It accepts an array that matches
6645 * the structure of the control.
6646 *
6647 * This method performs strict checks, and throws an error if you try
6648 * to set the value of a control that doesn't exist or if you exclude the
6649 * value of a control.
6650 *
6651 * @usageNotes
6652 * ### Set the values for the controls in the form array
6653 *
6654 * ```
6655 * const arr = new FormArray([
6656 * new FormControl(),
6657 * new FormControl()
6658 * ]);
6659 * console.log(arr.value); // [null, null]
6660 *
6661 * arr.setValue(['Nancy', 'Drew']);
6662 * console.log(arr.value); // ['Nancy', 'Drew']
6663 * ```
6664 *
6665 * @param value Array of values for the controls
6666 * @param options Configure options that determine how the control propagates changes and
6667 * emits events after the value changes
6668 *
6669 * * `onlySelf`: When true, each change only affects this control, and not its parent. Default
6670 * is false.
6671 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
6672 * `valueChanges`
6673 * observables emit events with the latest status and value when the control value is updated.
6674 * When false, no events are emitted.
6675 * The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
6676 * updateValueAndValidity} method.
6677 */
6678 setValue(value, options = {}) {
6679 assertAllValuesPresent(this, false, value);
6680 value.forEach((newValue, index) => {
6681 assertControlPresent(this, false, index);
6682 this.at(index).setValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
6683 });
6684 this.updateValueAndValidity(options);
6685 }
6686 /**
6687 * Patches the value of the `FormArray`. It accepts an array that matches the
6688 * structure of the control, and does its best to match the values to the correct
6689 * controls in the group.
6690 *
6691 * It accepts both super-sets and sub-sets of the array without throwing an error.
6692 *
6693 * @usageNotes
6694 * ### Patch the values for controls in a form array
6695 *
6696 * ```
6697 * const arr = new FormArray([
6698 * new FormControl(),
6699 * new FormControl()
6700 * ]);
6701 * console.log(arr.value); // [null, null]
6702 *
6703 * arr.patchValue(['Nancy']);
6704 * console.log(arr.value); // ['Nancy', null]
6705 * ```
6706 *
6707 * @param value Array of latest values for the controls
6708 * @param options Configure options that determine how the control propagates changes and
6709 * emits events after the value changes
6710 *
6711 * * `onlySelf`: When true, each change only affects this control, and not its parent. Default
6712 * is false.
6713 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
6714 * `valueChanges` observables emit events with the latest status and value when the control
6715 * value is updated. When false, no events are emitted. The configuration options are passed to
6716 * the {@link AbstractControl#updateValueAndValidity updateValueAndValidity} method.
6717 */
6718 patchValue(value, options = {}) {
6719 // Even though the `value` argument type doesn't allow `null` and `undefined` values, the
6720 // `patchValue` can be called recursively and inner data structures might have these values,
6721 // so we just ignore such cases when a field containing FormArray instance receives `null` or
6722 // `undefined` as a value.
6723 if (value == null /* both `null` and `undefined` */)
6724 return;
6725 value.forEach((newValue, index) => {
6726 if (this.at(index)) {
6727 this.at(index).patchValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
6728 }
6729 });
6730 this.updateValueAndValidity(options);
6731 }
6732 /**
6733 * Resets the `FormArray` and all descendants are marked `pristine` and `untouched`, and the
6734 * value of all descendants to null or null maps.
6735 *
6736 * You reset to a specific form state by passing in an array of states
6737 * that matches the structure of the control. The state is a standalone value
6738 * or a form state object with both a value and a disabled status.
6739 *
6740 * @usageNotes
6741 * ### Reset the values in a form array
6742 *
6743 * ```ts
6744 * const arr = new FormArray([
6745 * new FormControl(),
6746 * new FormControl()
6747 * ]);
6748 * arr.reset(['name', 'last name']);
6749 *
6750 * console.log(arr.value); // ['name', 'last name']
6751 * ```
6752 *
6753 * ### Reset the values in a form array and the disabled status for the first control
6754 *
6755 * ```
6756 * arr.reset([
6757 * {value: 'name', disabled: true},
6758 * 'last'
6759 * ]);
6760 *
6761 * console.log(arr.value); // ['last']
6762 * console.log(arr.at(0).status); // 'DISABLED'
6763 * ```
6764 *
6765 * @param value Array of values for the controls
6766 * @param options Configure options that determine how the control propagates changes and
6767 * emits events after the value changes
6768 *
6769 * * `onlySelf`: When true, each change only affects this control, and not its parent. Default
6770 * is false.
6771 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
6772 * `valueChanges`
6773 * observables emit events with the latest status and value when the control is reset.
6774 * When false, no events are emitted.
6775 * The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
6776 * updateValueAndValidity} method.
6777 */
6778 reset(value = [], options = {}) {
6779 this._forEachChild((control, index) => {
6780 control.reset(value[index], { onlySelf: true, emitEvent: options.emitEvent });
6781 });
6782 this._updatePristine(options);
6783 this._updateTouched(options);
6784 this.updateValueAndValidity(options);
6785 }
6786 /**
6787 * The aggregate value of the array, including any disabled controls.
6788 *
6789 * Reports all values regardless of disabled status.
6790 */
6791 getRawValue() {
6792 return this.controls.map((control) => control.getRawValue());
6793 }
6794 /**
6795 * Remove all controls in the `FormArray`.
6796 *
6797 * @param options Specifies whether this FormArray instance should emit events after all
6798 * controls are removed.
6799 * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
6800 * `valueChanges` observables emit events with the latest status and value when all controls
6801 * in this FormArray instance are removed. When false, no events are emitted.
6802 *
6803 * @usageNotes
6804 * ### Remove all elements from a FormArray
6805 *
6806 * ```ts
6807 * const arr = new FormArray([
6808 * new FormControl(),
6809 * new FormControl()
6810 * ]);
6811 * console.log(arr.length); // 2
6812 *
6813 * arr.clear();
6814 * console.log(arr.length); // 0
6815 * ```
6816 *
6817 * It's a simpler and more efficient alternative to removing all elements one by one:
6818 *
6819 * ```ts
6820 * const arr = new FormArray([
6821 * new FormControl(),
6822 * new FormControl()
6823 * ]);
6824 *
6825 * while (arr.length) {
6826 * arr.removeAt(0);
6827 * }
6828 * ```
6829 */
6830 clear(options = {}) {
6831 if (this.controls.length < 1)
6832 return;
6833 this._forEachChild((control) => control._registerOnCollectionChange(() => { }));
6834 this.controls.splice(0);
6835 this.updateValueAndValidity({ emitEvent: options.emitEvent });
6836 }
6837 /**
6838 * Adjusts a negative index by summing it with the length of the array. For very negative
6839 * indices, the result may remain negative.
6840 * @internal
6841 */
6842 _adjustIndex(index) {
6843 return index < 0 ? index + this.length : index;
6844 }
6845 /** @internal */
6846 _syncPendingControls() {
6847 let subtreeUpdated = this.controls.reduce((updated, child) => {
6848 return child._syncPendingControls() ? true : updated;
6849 }, false);
6850 if (subtreeUpdated)
6851 this.updateValueAndValidity({ onlySelf: true });
6852 return subtreeUpdated;
6853 }
6854 /** @internal */
6855 _forEachChild(cb) {
6856 this.controls.forEach((control, index) => {
6857 cb(control, index);
6858 });
6859 }
6860 /** @internal */
6861 _updateValue() {
6862 this.value =
6863 this.controls.filter((control) => control.enabled || this.disabled)
6864 .map((control) => control.value);
6865 }
6866 /** @internal */
6867 _anyControls(condition) {
6868 return this.controls.some((control) => control.enabled && condition(control));
6869 }
6870 /** @internal */
6871 _setUpControls() {
6872 this._forEachChild((control) => this._registerControl(control));
6873 }
6874 /** @internal */
6875 _allControlsDisabled() {
6876 for (const control of this.controls) {
6877 if (control.enabled)
6878 return false;
6879 }
6880 return this.controls.length > 0 || this.disabled;
6881 }
6882 _registerControl(control) {
6883 control.setParent(this);
6884 control._registerOnCollectionChange(this._onCollectionChange);
6885 }
6886 /** @internal */
6887 _find(name) {
6888 return this.at(name) ?? null;
6889 }
6890}
6891const UntypedFormArray = FormArray;
6892/**
6893 * @description
6894 * Asserts that the given control is an instance of `FormArray`
6895 *
6896 * @publicApi
6897 */
6898const isFormArray = (control) => control instanceof FormArray;
6899
6900function isAbstractControlOptions(options) {
6901 return !!options &&
6902 (options.asyncValidators !== undefined ||
6903 options.validators !== undefined ||
6904 options.updateOn !== undefined);
6905}
6906// clang-format on
6907/**
6908 * @description
6909 * Creates an `AbstractControl` from a user-specified configuration.
6910 *
6911 * The `FormBuilder` provides syntactic sugar that shortens creating instances of a
6912 * `FormControl`, `FormGroup`, or `FormArray`. It reduces the amount of boilerplate needed to
6913 * build complex forms.
6914 *
6915 * @see [Reactive Forms Guide](guide/reactive-forms)
6916 *
6917 * @publicApi
6918 */
6919class FormBuilder {
6920 constructor() {
6921 this.useNonNullable = false;
6922 }
6923 /**
6924 * @description
6925 * Returns a FormBuilder in which automatically constructed `FormControl` elements
6926 * have `{nonNullable: true}` and are non-nullable.
6927 *
6928 * **Constructing non-nullable controls**
6929 *
6930 * When constructing a control, it will be non-nullable, and will reset to its initial value.
6931 *
6932 * ```ts
6933 * let nnfb = new FormBuilder().nonNullable;
6934 * let name = nnfb.control('Alex'); // FormControl<string>
6935 * name.reset();
6936 * console.log(name); // 'Alex'
6937 * ```
6938 *
6939 * **Constructing non-nullable groups or arrays**
6940 *
6941 * When constructing a group or array, all automatically created inner controls will be
6942 * non-nullable, and will reset to their initial values.
6943 *
6944 * ```ts
6945 * let nnfb = new FormBuilder().nonNullable;
6946 * let name = nnfb.group({who: 'Alex'}); // FormGroup<{who: FormControl<string>}>
6947 * name.reset();
6948 * console.log(name); // {who: 'Alex'}
6949 * ```
6950 * **Constructing *nullable* fields on groups or arrays**
6951 *
6952 * It is still possible to have a nullable field. In particular, any `FormControl` which is
6953 * *already* constructed will not be altered. For example:
6954 *
6955 * ```ts
6956 * let nnfb = new FormBuilder().nonNullable;
6957 * // FormGroup<{who: FormControl<string|null>}>
6958 * let name = nnfb.group({who: new FormControl('Alex')});
6959 * name.reset(); console.log(name); // {who: null}
6960 * ```
6961 *
6962 * Because the inner control is constructed explicitly by the caller, the builder has
6963 * no control over how it is created, and cannot exclude the `null`.
6964 */
6965 get nonNullable() {
6966 const nnfb = new FormBuilder();
6967 nnfb.useNonNullable = true;
6968 return nnfb;
6969 }
6970 group(controls, options = null) {
6971 const reducedControls = this._reduceControls(controls);
6972 let newOptions = {};
6973 if (isAbstractControlOptions(options)) {
6974 // `options` are `AbstractControlOptions`
6975 newOptions = options;
6976 }
6977 else if (options !== null) {
6978 // `options` are legacy form group options
6979 newOptions.validators = options.validator;
6980 newOptions.asyncValidators = options.asyncValidator;
6981 }
6982 return new FormGroup(reducedControls, newOptions);
6983 }
6984 /**
6985 * @description
6986 * Constructs a new `FormRecord` instance. Accepts a single generic argument, which is an object
6987 * containing all the keys and corresponding inner control types.
6988 *
6989 * @param controls A collection of child controls. The key for each child is the name
6990 * under which it is registered.
6991 *
6992 * @param options Configuration options object for the `FormRecord`. The object should have the
6993 * `AbstractControlOptions` type and might contain the following fields:
6994 * * `validators`: A synchronous validator function, or an array of validator functions.
6995 * * `asyncValidators`: A single async validator or array of async validator functions.
6996 * * `updateOn`: The event upon which the control should be updated (options: 'change' | 'blur'
6997 * | submit').
6998 */
6999 record(controls, options = null) {
7000 const reducedControls = this._reduceControls(controls);
7001 // Cast to `any` because the inferred types are not as specific as Element.
7002 return new FormRecord(reducedControls, options);
7003 }
7004 /**
7005 * @description
7006 * Constructs a new `FormControl` with the given state, validators and options. Sets
7007 * `{nonNullable: true}` in the options to get a non-nullable control. Otherwise, the
7008 * control will be nullable. Accepts a single generic argument, which is the type of the
7009 * control's value.
7010 *
7011 * @param formState Initializes the control with an initial state value, or
7012 * with an object that contains both a value and a disabled status.
7013 *
7014 * @param validatorOrOpts A synchronous validator function, or an array of
7015 * such functions, or a `FormControlOptions` object that contains
7016 * validation functions and a validation trigger.
7017 *
7018 * @param asyncValidator A single async validator or array of async validator
7019 * functions.
7020 *
7021 * @usageNotes
7022 *
7023 * ### Initialize a control as disabled
7024 *
7025 * The following example returns a control with an initial value in a disabled state.
7026 *
7027 * <code-example path="forms/ts/formBuilder/form_builder_example.ts" region="disabled-control">
7028 * </code-example>
7029 */
7030 control(formState, validatorOrOpts, asyncValidator) {
7031 let newOptions = {};
7032 if (!this.useNonNullable) {
7033 return new FormControl(formState, validatorOrOpts, asyncValidator);
7034 }
7035 if (isAbstractControlOptions(validatorOrOpts)) {
7036 // If the second argument is options, then they are copied.
7037 newOptions = validatorOrOpts;
7038 }
7039 else {
7040 // If the other arguments are validators, they are copied into an options object.
7041 newOptions.validators = validatorOrOpts;
7042 newOptions.asyncValidators = asyncValidator;
7043 }
7044 return new FormControl(formState, { ...newOptions, nonNullable: true });
7045 }
7046 /**
7047 * Constructs a new `FormArray` from the given array of configurations,
7048 * validators and options. Accepts a single generic argument, which is the type of each control
7049 * inside the array.
7050 *
7051 * @param controls An array of child controls or control configs. Each child control is given an
7052 * index when it is registered.
7053 *
7054 * @param validatorOrOpts A synchronous validator function, or an array of such functions, or an
7055 * `AbstractControlOptions` object that contains
7056 * validation functions and a validation trigger.
7057 *
7058 * @param asyncValidator A single async validator or array of async validator functions.
7059 */
7060 array(controls, validatorOrOpts, asyncValidator) {
7061 const createdControls = controls.map(c => this._createControl(c));
7062 // Cast to `any` because the inferred types are not as specific as Element.
7063 return new FormArray(createdControls, validatorOrOpts, asyncValidator);
7064 }
7065 /** @internal */
7066 _reduceControls(controls) {
7067 const createdControls = {};
7068 Object.keys(controls).forEach(controlName => {
7069 createdControls[controlName] = this._createControl(controls[controlName]);
7070 });
7071 return createdControls;
7072 }
7073 /** @internal */
7074 _createControl(controls) {
7075 if (controls instanceof FormControl) {
7076 return controls;
7077 }
7078 else if (controls instanceof AbstractControl) { // A control; just return it
7079 return controls;
7080 }
7081 else if (Array.isArray(controls)) { // ControlConfig Tuple
7082 const value = controls[0];
7083 const validator = controls.length > 1 ? controls[1] : null;
7084 const asyncValidator = controls.length > 2 ? controls[2] : null;
7085 return this.control(value, validator, asyncValidator);
7086 }
7087 else { // T or FormControlState<T>
7088 return this.control(controls);
7089 }
7090 }
7091 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormBuilder, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
7092 static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormBuilder, providedIn: 'root' }); }
7093}
7094i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormBuilder, decorators: [{
7095 type: Injectable,
7096 args: [{ providedIn: 'root' }]
7097 }] });
7098/**
7099 * @description
7100 * `NonNullableFormBuilder` is similar to {@link FormBuilder}, but automatically constructed
7101 * {@link FormControl} elements have `{nonNullable: true}` and are non-nullable.
7102 *
7103 * @publicApi
7104 */
7105class NonNullableFormBuilder {
7106 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NonNullableFormBuilder, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
7107 static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NonNullableFormBuilder, providedIn: 'root', useFactory: () => inject(FormBuilder).nonNullable }); }
7108}
7109i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: NonNullableFormBuilder, decorators: [{
7110 type: Injectable,
7111 args: [{
7112 providedIn: 'root',
7113 useFactory: () => inject(FormBuilder).nonNullable,
7114 }]
7115 }] });
7116/**
7117 * UntypedFormBuilder is the same as `FormBuilder`, but it provides untyped controls.
7118 */
7119class UntypedFormBuilder extends FormBuilder {
7120 group(controlsConfig, options = null) {
7121 return super.group(controlsConfig, options);
7122 }
7123 /**
7124 * Like `FormBuilder#control`, except the resulting control is untyped.
7125 */
7126 control(formState, validatorOrOpts, asyncValidator) {
7127 return super.control(formState, validatorOrOpts, asyncValidator);
7128 }
7129 /**
7130 * Like `FormBuilder#array`, except the resulting array is untyped.
7131 */
7132 array(controlsConfig, validatorOrOpts, asyncValidator) {
7133 return super.array(controlsConfig, validatorOrOpts, asyncValidator);
7134 }
7135 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: UntypedFormBuilder, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
7136 static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: UntypedFormBuilder, providedIn: 'root' }); }
7137}
7138i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: UntypedFormBuilder, decorators: [{
7139 type: Injectable,
7140 args: [{ providedIn: 'root' }]
7141 }] });
7142
7143/**
7144 * @module
7145 * @description
7146 * Entry point for all public APIs of the forms package.
7147 */
7148/**
7149 * @publicApi
7150 */
7151const VERSION = new Version('17.3.5');
7152
7153/**
7154 * Exports the required providers and directives for template-driven forms,
7155 * making them available for import by NgModules that import this module.
7156 *
7157 * @see [Forms Overview](/guide/forms-overview)
7158 * @see [Template-driven Forms Guide](/guide/forms)
7159 *
7160 * @publicApi
7161 */
7162class FormsModule {
7163 /**
7164 * @description
7165 * Provides options for configuring the forms module.
7166 *
7167 * @param opts An object of configuration options
7168 * * `callSetDisabledState` Configures whether to `always` call `setDisabledState`, which is more
7169 * correct, or to only call it `whenDisabled`, which is the legacy behavior.
7170 */
7171 static withConfig(opts) {
7172 return {
7173 ngModule: FormsModule,
7174 providers: [{
7175 provide: CALL_SET_DISABLED_STATE,
7176 useValue: opts.callSetDisabledState ?? setDisabledStateDefault
7177 }]
7178 };
7179 }
7180 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
7181 static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.5", ngImport: i0, type: FormsModule, declarations: [NgModel, NgModelGroup, NgForm], exports: [ɵInternalFormsSharedModule, NgModel, NgModelGroup, NgForm] }); }
7182 static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormsModule, imports: [ɵInternalFormsSharedModule] }); }
7183}
7184i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: FormsModule, decorators: [{
7185 type: NgModule,
7186 args: [{
7187 declarations: TEMPLATE_DRIVEN_DIRECTIVES,
7188 exports: [ɵInternalFormsSharedModule, TEMPLATE_DRIVEN_DIRECTIVES]
7189 }]
7190 }] });
7191/**
7192 * Exports the required infrastructure and directives for reactive forms,
7193 * making them available for import by NgModules that import this module.
7194 *
7195 * @see [Forms Overview](guide/forms-overview)
7196 * @see [Reactive Forms Guide](guide/reactive-forms)
7197 *
7198 * @publicApi
7199 */
7200class ReactiveFormsModule {
7201 /**
7202 * @description
7203 * Provides options for configuring the reactive forms module.
7204 *
7205 * @param opts An object of configuration options
7206 * * `warnOnNgModelWithFormControl` Configures when to emit a warning when an `ngModel`
7207 * binding is used with reactive form directives.
7208 * * `callSetDisabledState` Configures whether to `always` call `setDisabledState`, which is more
7209 * correct, or to only call it `whenDisabled`, which is the legacy behavior.
7210 */
7211 static withConfig(opts) {
7212 return {
7213 ngModule: ReactiveFormsModule,
7214 providers: [
7215 {
7216 provide: NG_MODEL_WITH_FORM_CONTROL_WARNING,
7217 useValue: opts.warnOnNgModelWithFormControl ?? 'always'
7218 },
7219 {
7220 provide: CALL_SET_DISABLED_STATE,
7221 useValue: opts.callSetDisabledState ?? setDisabledStateDefault
7222 }
7223 ]
7224 };
7225 }
7226 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ReactiveFormsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
7227 static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.5", ngImport: i0, type: ReactiveFormsModule, declarations: [FormControlDirective, FormGroupDirective, FormControlName, FormGroupName, FormArrayName], exports: [ɵInternalFormsSharedModule, FormControlDirective, FormGroupDirective, FormControlName, FormGroupName, FormArrayName] }); }
7228 static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ReactiveFormsModule, imports: [ɵInternalFormsSharedModule] }); }
7229}
7230i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ReactiveFormsModule, decorators: [{
7231 type: NgModule,
7232 args: [{
7233 declarations: [REACTIVE_DRIVEN_DIRECTIVES],
7234 exports: [ɵInternalFormsSharedModule, REACTIVE_DRIVEN_DIRECTIVES]
7235 }]
7236 }] });
7237
7238/**
7239 * @module
7240 * @description
7241 * This module is used for handling user input, by defining and building a `FormGroup` that
7242 * consists of `FormControl` objects, and mapping them onto the DOM. `FormControl`
7243 * objects can then be used to read information from the form DOM elements.
7244 *
7245 * Forms providers are not included in default providers; you must import these providers
7246 * explicitly.
7247 */
7248
7249/**
7250 * @module
7251 * @description
7252 * Entry point for all public APIs of this package.
7253 */
7254// This file only reexports content of the `src` folder. Keep it that way.
7255
7256// This file is not used to build this module. It is only used during editing
7257
7258/**
7259 * Generated bundle index. Do not edit.
7260 */
7261
7262export { AbstractControl, AbstractControlDirective, AbstractFormGroupDirective, COMPOSITION_BUFFER_MODE, CheckboxControlValueAccessor, CheckboxRequiredValidator, ControlContainer, DefaultValueAccessor, EmailValidator, FormArray, FormArrayName, FormBuilder, FormControl, FormControlDirective, FormControlName, FormGroup, FormGroupDirective, FormGroupName, FormRecord, FormsModule, MaxLengthValidator, MaxValidator, MinLengthValidator, MinValidator, NG_ASYNC_VALIDATORS, NG_VALIDATORS, NG_VALUE_ACCESSOR, NgControl, NgControlStatus, NgControlStatusGroup, NgForm, NgModel, NgModelGroup, NgSelectOption, NonNullableFormBuilder, NumberValueAccessor, PatternValidator, RadioControlValueAccessor, RangeValueAccessor, ReactiveFormsModule, RequiredValidator, SelectControlValueAccessor, SelectMultipleControlValueAccessor, UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, VERSION, Validators, isFormArray, isFormControl, isFormGroup, isFormRecord, ɵInternalFormsSharedModule, ɵNgNoValidate, ɵNgSelectMultipleOption };
7263//# sourceMappingURL=forms.mjs.map