source: trip-planner-front/node_modules/@angular/forms/fesm2015/forms.js@ 1ad8e64

Last change on this file since 1ad8e64 was e29cc2e, checked in by Ema <ema_spirova@…>, 3 years ago

primeNG components

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