@angular/forms 21.0.0-next.0 → 21.0.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/forms.mjs +2152 -2061
- package/fesm2022/forms.mjs.map +1 -1
- package/index.d.ts +128 -53
- package/package.json +4 -4
package/fesm2022/forms.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v21.0.0-next.
|
|
2
|
+
* @license Angular v21.0.0-next.1
|
|
3
3
|
* (c) 2010-2025 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -1401,12 +1401,12 @@ class NgControlStatusGroup extends AbstractControlStatus {
|
|
|
1401
1401
|
super(cd);
|
|
1402
1402
|
}
|
|
1403
1403
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: NgControlStatusGroup, deps: [{ token: ControlContainer, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1404
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: NgControlStatusGroup, isStandalone: false, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]", host: { properties: { "class.ng-untouched": "isUntouched", "class.ng-touched": "isTouched", "class.ng-pristine": "isPristine", "class.ng-dirty": "isDirty", "class.ng-valid": "isValid", "class.ng-invalid": "isInvalid", "class.ng-pending": "isPending", "class.ng-submitted": "isSubmitted" } }, usesInheritance: true, ngImport: i0 });
|
|
1404
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: NgControlStatusGroup, isStandalone: false, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]", host: { properties: { "class.ng-untouched": "isUntouched", "class.ng-touched": "isTouched", "class.ng-pristine": "isPristine", "class.ng-dirty": "isDirty", "class.ng-valid": "isValid", "class.ng-invalid": "isInvalid", "class.ng-pending": "isPending", "class.ng-submitted": "isSubmitted" } }, usesInheritance: true, ngImport: i0 });
|
|
1405
1405
|
}
|
|
1406
1406
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: NgControlStatusGroup, decorators: [{
|
|
1407
1407
|
type: Directive,
|
|
1408
1408
|
args: [{
|
|
1409
|
-
selector: '[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]',
|
|
1409
|
+
selector: '[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]',
|
|
1410
1410
|
host: ngGroupStatusHost,
|
|
1411
1411
|
standalone: false,
|
|
1412
1412
|
}]
|
|
@@ -1467,8 +1467,8 @@ const ngModelWithFormGroupExample = `
|
|
|
1467
1467
|
`;
|
|
1468
1468
|
|
|
1469
1469
|
function controlParentException(nameOrIndex) {
|
|
1470
|
-
return new _RuntimeError(1050 /* RuntimeErrorCode.FORM_CONTROL_NAME_MISSING_PARENT */, `formControlName must be used with a parent formGroup directive.
|
|
1471
|
-
directive and pass it an existing FormGroup instance (you can create one in your class).
|
|
1470
|
+
return new _RuntimeError(1050 /* RuntimeErrorCode.FORM_CONTROL_NAME_MISSING_PARENT */, `formControlName must be used with a parent formGroup or formArray directive. You'll want to add a formGroup/formArray
|
|
1471
|
+
directive and pass it an existing FormGroup/FormArray instance (you can create one in your class).
|
|
1472
1472
|
|
|
1473
1473
|
${describeFormControl(nameOrIndex)}
|
|
1474
1474
|
|
|
@@ -3481,7 +3481,7 @@ function _ngModelWarning(name, type, instance, warningConfig) {
|
|
|
3481
3481
|
}
|
|
3482
3482
|
}
|
|
3483
3483
|
|
|
3484
|
-
const formDirectiveProvider$
|
|
3484
|
+
const formDirectiveProvider$2 = {
|
|
3485
3485
|
provide: ControlContainer,
|
|
3486
3486
|
useExisting: forwardRef(() => NgForm),
|
|
3487
3487
|
};
|
|
@@ -3764,13 +3764,13 @@ class NgForm extends ControlContainer {
|
|
|
3764
3764
|
return path.length ? this.form.get(path) : this.form;
|
|
3765
3765
|
}
|
|
3766
3766
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: NgForm, deps: [{ token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: CALL_SET_DISABLED_STATE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
3767
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: NgForm, isStandalone: false, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: { options: ["ngFormOptions", "options"] }, outputs: { ngSubmit: "ngSubmit" }, host: { listeners: { "submit": "onSubmit($event)", "reset": "onReset()" } }, providers: [formDirectiveProvider$
|
|
3767
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: NgForm, isStandalone: false, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: { options: ["ngFormOptions", "options"] }, outputs: { ngSubmit: "ngSubmit" }, host: { listeners: { "submit": "onSubmit($event)", "reset": "onReset()" } }, providers: [formDirectiveProvider$2], exportAs: ["ngForm"], usesInheritance: true, ngImport: i0 });
|
|
3768
3768
|
}
|
|
3769
3769
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: NgForm, decorators: [{
|
|
3770
3770
|
type: Directive,
|
|
3771
3771
|
args: [{
|
|
3772
|
-
selector: 'form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]',
|
|
3773
|
-
providers: [formDirectiveProvider$
|
|
3772
|
+
selector: 'form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]',
|
|
3773
|
+
providers: [formDirectiveProvider$2],
|
|
3774
3774
|
host: { '(submit)': 'onSubmit($event)', '(reset)': 'onReset()' },
|
|
3775
3775
|
outputs: ['ngSubmit'],
|
|
3776
3776
|
exportAs: 'ngForm',
|
|
@@ -4833,941 +4833,758 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2",
|
|
|
4833
4833
|
}] });
|
|
4834
4834
|
|
|
4835
4835
|
/**
|
|
4836
|
-
*
|
|
4837
|
-
|
|
4838
|
-
const NG_MODEL_WITH_FORM_CONTROL_WARNING = new InjectionToken(ngDevMode ? 'NgModelWithFormControlWarning' : '');
|
|
4839
|
-
const formControlBinding = {
|
|
4840
|
-
provide: NgControl,
|
|
4841
|
-
useExisting: forwardRef(() => FormControlDirective),
|
|
4842
|
-
};
|
|
4843
|
-
/**
|
|
4844
|
-
* @description
|
|
4845
|
-
* Synchronizes a standalone `FormControl` instance to a form control element.
|
|
4836
|
+
* Tracks the value and validity state of an array of `FormControl`,
|
|
4837
|
+
* `FormGroup` or `FormArray` instances.
|
|
4846
4838
|
*
|
|
4847
|
-
*
|
|
4848
|
-
*
|
|
4849
|
-
* a
|
|
4839
|
+
* A `FormArray` aggregates the values of each child `FormControl` into an array.
|
|
4840
|
+
* It calculates its status by reducing the status values of its children. For example, if one of
|
|
4841
|
+
* the controls in a `FormArray` is invalid, the entire array becomes invalid.
|
|
4850
4842
|
*
|
|
4851
|
-
*
|
|
4852
|
-
*
|
|
4853
|
-
*
|
|
4843
|
+
* `FormArray` accepts one generic argument, which is the type of the controls inside.
|
|
4844
|
+
* If you need a heterogenous array, use {@link UntypedFormArray}.
|
|
4845
|
+
*
|
|
4846
|
+
* `FormArray` is one of the four fundamental building blocks used to define forms in Angular,
|
|
4847
|
+
* along with `FormControl`, `FormGroup`, and `FormRecord`.
|
|
4854
4848
|
*
|
|
4855
4849
|
* @usageNotes
|
|
4856
4850
|
*
|
|
4857
|
-
*
|
|
4851
|
+
* ### Create an array of form controls
|
|
4858
4852
|
*
|
|
4859
|
-
*
|
|
4853
|
+
* ```ts
|
|
4854
|
+
* const arr = new FormArray([
|
|
4855
|
+
* new FormControl('Nancy', Validators.minLength(2)),
|
|
4856
|
+
* new FormControl('Drew'),
|
|
4857
|
+
* ]);
|
|
4858
|
+
*
|
|
4859
|
+
* console.log(arr.value); // ['Nancy', 'Drew']
|
|
4860
|
+
* console.log(arr.status); // 'VALID'
|
|
4861
|
+
* ```
|
|
4862
|
+
*
|
|
4863
|
+
* ### Create a form array with array-level validators
|
|
4864
|
+
*
|
|
4865
|
+
* You include array-level validators and async validators. These come in handy
|
|
4866
|
+
* when you want to perform validation that considers the value of more than one child
|
|
4867
|
+
* control.
|
|
4868
|
+
*
|
|
4869
|
+
* The two types of validators are passed in separately as the second and third arg
|
|
4870
|
+
* respectively, or together as part of an options object.
|
|
4871
|
+
*
|
|
4872
|
+
* ```ts
|
|
4873
|
+
* const arr = new FormArray([
|
|
4874
|
+
* new FormControl('Nancy'),
|
|
4875
|
+
* new FormControl('Drew')
|
|
4876
|
+
* ], {validators: myValidator, asyncValidators: myAsyncValidator});
|
|
4877
|
+
* ```
|
|
4878
|
+
*
|
|
4879
|
+
* ### Set the updateOn property for all controls in a form array
|
|
4880
|
+
*
|
|
4881
|
+
* The options object is used to set a default value for each child
|
|
4882
|
+
* control's `updateOn` property. If you set `updateOn` to `'blur'` at the
|
|
4883
|
+
* array level, all child controls default to 'blur', unless the child
|
|
4884
|
+
* has explicitly specified a different `updateOn` value.
|
|
4885
|
+
*
|
|
4886
|
+
* ```ts
|
|
4887
|
+
* const arr = new FormArray([
|
|
4888
|
+
* new FormControl()
|
|
4889
|
+
* ], {updateOn: 'blur'});
|
|
4890
|
+
* ```
|
|
4891
|
+
*
|
|
4892
|
+
* ### Adding or removing controls from a form array
|
|
4893
|
+
*
|
|
4894
|
+
* To change the controls in the array, use the `push`, `insert`, `removeAt` or `clear` methods
|
|
4895
|
+
* in `FormArray` itself. These methods ensure the controls are properly tracked in the
|
|
4896
|
+
* form's hierarchy. Do not modify the array of `AbstractControl`s used to instantiate
|
|
4897
|
+
* the `FormArray` directly, as that result in strange and unexpected behavior such
|
|
4898
|
+
* as broken change detection.
|
|
4860
4899
|
*
|
|
4861
|
-
* @ngModule ReactiveFormsModule
|
|
4862
4900
|
* @publicApi
|
|
4863
4901
|
*/
|
|
4864
|
-
class
|
|
4865
|
-
_ngModelWarningConfig;
|
|
4866
|
-
callSetDisabledState;
|
|
4867
|
-
/**
|
|
4868
|
-
* Internal reference to the view model value.
|
|
4869
|
-
* @docs-private
|
|
4870
|
-
*/
|
|
4871
|
-
viewModel;
|
|
4872
|
-
/**
|
|
4873
|
-
* @description
|
|
4874
|
-
* Tracks the `FormControl` instance bound to the directive.
|
|
4875
|
-
*/
|
|
4876
|
-
form;
|
|
4902
|
+
class FormArray extends AbstractControl {
|
|
4877
4903
|
/**
|
|
4878
|
-
*
|
|
4879
|
-
*
|
|
4904
|
+
* Creates a new `FormArray` instance.
|
|
4905
|
+
*
|
|
4906
|
+
* @param controls An array of child controls. Each child control is given an index
|
|
4907
|
+
* where it is registered.
|
|
4908
|
+
*
|
|
4909
|
+
* @param validatorOrOpts A synchronous validator function, or an array of
|
|
4910
|
+
* such functions, or an `AbstractControlOptions` object that contains validation functions
|
|
4911
|
+
* and a validation trigger.
|
|
4912
|
+
*
|
|
4913
|
+
* @param asyncValidator A single async validator or array of async validator functions
|
|
4914
|
+
*
|
|
4880
4915
|
*/
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4916
|
+
constructor(controls, validatorOrOpts, asyncValidator) {
|
|
4917
|
+
super(pickValidators(validatorOrOpts), pickAsyncValidators(asyncValidator, validatorOrOpts));
|
|
4918
|
+
this.controls = controls;
|
|
4919
|
+
this._initObservables();
|
|
4920
|
+
this._setUpdateStrategy(validatorOrOpts);
|
|
4921
|
+
this._setUpControls();
|
|
4922
|
+
this.updateValueAndValidity({
|
|
4923
|
+
onlySelf: true,
|
|
4924
|
+
// If `asyncValidator` is present, it will trigger control status change from `PENDING` to
|
|
4925
|
+
// `VALID` or `INVALID`.
|
|
4926
|
+
// The status should be broadcasted via the `statusChanges` observable, so we set `emitEvent`
|
|
4927
|
+
// to `true` to allow that during the control creation process.
|
|
4928
|
+
emitEvent: !!this.asyncValidator,
|
|
4929
|
+
});
|
|
4885
4930
|
}
|
|
4886
|
-
|
|
4887
|
-
/** @deprecated as of v6 */
|
|
4888
|
-
model;
|
|
4889
|
-
/** @deprecated as of v6 */
|
|
4890
|
-
update = new EventEmitter();
|
|
4931
|
+
controls;
|
|
4891
4932
|
/**
|
|
4892
|
-
*
|
|
4893
|
-
* Static property used to track whether any ngModel warnings have been sent across
|
|
4894
|
-
* all instances of FormControlDirective. Used to support warning config of "once".
|
|
4933
|
+
* Get the `AbstractControl` at the given `index` in the array.
|
|
4895
4934
|
*
|
|
4896
|
-
* @
|
|
4935
|
+
* @param index Index in the array to retrieve the control. If `index` is negative, it will wrap
|
|
4936
|
+
* around from the back, and if index is greatly negative (less than `-length`), the result is
|
|
4937
|
+
* undefined. This behavior is the same as `Array.at(index)`.
|
|
4897
4938
|
*/
|
|
4898
|
-
|
|
4939
|
+
at(index) {
|
|
4940
|
+
return this.controls[this._adjustIndex(index)];
|
|
4941
|
+
}
|
|
4899
4942
|
/**
|
|
4900
|
-
*
|
|
4901
|
-
* Instance property used to track whether an ngModel warning has been sent out for this
|
|
4902
|
-
* particular `FormControlDirective` instance. Used to support warning config of "always".
|
|
4943
|
+
* Insert a new `AbstractControl` at the end of the array.
|
|
4903
4944
|
*
|
|
4904
|
-
* @
|
|
4945
|
+
* @param control Form control to be inserted
|
|
4946
|
+
* @param options Specifies whether this FormArray instance should emit events after a new
|
|
4947
|
+
* control is added.
|
|
4948
|
+
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
|
4949
|
+
* `valueChanges` observables emit events with the latest status and value when the control is
|
|
4950
|
+
* inserted. When false, no events are emitted.
|
|
4905
4951
|
*/
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
this._setAsyncValidators(asyncValidators);
|
|
4913
|
-
this.valueAccessor = selectValueAccessor(this, valueAccessors);
|
|
4914
|
-
}
|
|
4915
|
-
/** @docs-private */
|
|
4916
|
-
ngOnChanges(changes) {
|
|
4917
|
-
if (this._isControlChanged(changes)) {
|
|
4918
|
-
const previousForm = changes['form'].previousValue;
|
|
4919
|
-
if (previousForm) {
|
|
4920
|
-
cleanUpControl(previousForm, this, /* validateControlPresenceOnChange */ false);
|
|
4921
|
-
}
|
|
4922
|
-
setUpControl(this.form, this, this.callSetDisabledState);
|
|
4923
|
-
this.form.updateValueAndValidity({ emitEvent: false });
|
|
4924
|
-
}
|
|
4925
|
-
if (isPropertyUpdated(changes, this.viewModel)) {
|
|
4926
|
-
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
4927
|
-
_ngModelWarning('formControl', FormControlDirective, this, this._ngModelWarningConfig);
|
|
4928
|
-
}
|
|
4929
|
-
this.form.setValue(this.model);
|
|
4930
|
-
this.viewModel = this.model;
|
|
4952
|
+
push(control, options = {}) {
|
|
4953
|
+
if (Array.isArray(control)) {
|
|
4954
|
+
control.forEach((ctrl) => {
|
|
4955
|
+
this.controls.push(ctrl);
|
|
4956
|
+
this._registerControl(ctrl);
|
|
4957
|
+
});
|
|
4931
4958
|
}
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
if (this.form) {
|
|
4936
|
-
cleanUpControl(this.form, this, /* validateControlPresenceOnChange */ false);
|
|
4959
|
+
else {
|
|
4960
|
+
this.controls.push(control);
|
|
4961
|
+
this._registerControl(control);
|
|
4937
4962
|
}
|
|
4963
|
+
this.updateValueAndValidity({ emitEvent: options.emitEvent });
|
|
4964
|
+
this._onCollectionChange();
|
|
4938
4965
|
}
|
|
4939
4966
|
/**
|
|
4940
|
-
*
|
|
4941
|
-
*
|
|
4942
|
-
*
|
|
4967
|
+
* Insert a new `AbstractControl` at the given `index` in the array.
|
|
4968
|
+
*
|
|
4969
|
+
* @param index Index in the array to insert the control. If `index` is negative, wraps around
|
|
4970
|
+
* from the back. If `index` is greatly negative (less than `-length`), prepends to the array.
|
|
4971
|
+
* This behavior is the same as `Array.splice(index, 0, control)`.
|
|
4972
|
+
* @param control Form control to be inserted
|
|
4973
|
+
* @param options Specifies whether this FormArray instance should emit events after a new
|
|
4974
|
+
* control is inserted.
|
|
4975
|
+
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
|
4976
|
+
* `valueChanges` observables emit events with the latest status and value when the control is
|
|
4977
|
+
* inserted. When false, no events are emitted.
|
|
4943
4978
|
*/
|
|
4944
|
-
|
|
4945
|
-
|
|
4979
|
+
insert(index, control, options = {}) {
|
|
4980
|
+
this.controls.splice(index, 0, control);
|
|
4981
|
+
this._registerControl(control);
|
|
4982
|
+
this.updateValueAndValidity({ emitEvent: options.emitEvent });
|
|
4946
4983
|
}
|
|
4947
4984
|
/**
|
|
4948
|
-
*
|
|
4949
|
-
*
|
|
4985
|
+
* Remove the control at the given `index` in the array.
|
|
4986
|
+
*
|
|
4987
|
+
* @param index Index in the array to remove the control. If `index` is negative, wraps around
|
|
4988
|
+
* from the back. If `index` is greatly negative (less than `-length`), removes the first
|
|
4989
|
+
* element. This behavior is the same as `Array.splice(index, 1)`.
|
|
4990
|
+
* @param options Specifies whether this FormArray instance should emit events after a
|
|
4991
|
+
* control is removed.
|
|
4992
|
+
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
|
4993
|
+
* `valueChanges` observables emit events with the latest status and value when the control is
|
|
4994
|
+
* removed. When false, no events are emitted.
|
|
4950
4995
|
*/
|
|
4951
|
-
|
|
4952
|
-
|
|
4996
|
+
removeAt(index, options = {}) {
|
|
4997
|
+
// Adjust the index, then clamp it at no less than 0 to prevent undesired underflows.
|
|
4998
|
+
let adjustedIndex = this._adjustIndex(index);
|
|
4999
|
+
if (adjustedIndex < 0)
|
|
5000
|
+
adjustedIndex = 0;
|
|
5001
|
+
if (this.controls[adjustedIndex])
|
|
5002
|
+
this.controls[adjustedIndex]._registerOnCollectionChange(() => { });
|
|
5003
|
+
this.controls.splice(adjustedIndex, 1);
|
|
5004
|
+
this.updateValueAndValidity({ emitEvent: options.emitEvent });
|
|
4953
5005
|
}
|
|
4954
5006
|
/**
|
|
4955
|
-
*
|
|
4956
|
-
* Sets the new value for the view model and emits an `ngModelChange` event.
|
|
5007
|
+
* Replace an existing control.
|
|
4957
5008
|
*
|
|
4958
|
-
* @param
|
|
5009
|
+
* @param index Index in the array to replace the control. If `index` is negative, wraps around
|
|
5010
|
+
* from the back. If `index` is greatly negative (less than `-length`), replaces the first
|
|
5011
|
+
* element. This behavior is the same as `Array.splice(index, 1, control)`.
|
|
5012
|
+
* @param control The `AbstractControl` control to replace the existing control
|
|
5013
|
+
* @param options Specifies whether this FormArray instance should emit events after an
|
|
5014
|
+
* existing control is replaced with a new one.
|
|
5015
|
+
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
|
5016
|
+
* `valueChanges` observables emit events with the latest status and value when the control is
|
|
5017
|
+
* replaced with a new one. When false, no events are emitted.
|
|
4959
5018
|
*/
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
this.
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
type: Directive,
|
|
4972
|
-
args: [{
|
|
4973
|
-
selector: '[formControl]',
|
|
4974
|
-
providers: [formControlBinding],
|
|
4975
|
-
exportAs: 'ngForm',
|
|
4976
|
-
standalone: false,
|
|
4977
|
-
}]
|
|
4978
|
-
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
4979
|
-
type: Optional
|
|
4980
|
-
}, {
|
|
4981
|
-
type: Self
|
|
4982
|
-
}, {
|
|
4983
|
-
type: Inject,
|
|
4984
|
-
args: [NG_VALIDATORS]
|
|
4985
|
-
}] }, { type: undefined, decorators: [{
|
|
4986
|
-
type: Optional
|
|
4987
|
-
}, {
|
|
4988
|
-
type: Self
|
|
4989
|
-
}, {
|
|
4990
|
-
type: Inject,
|
|
4991
|
-
args: [NG_ASYNC_VALIDATORS]
|
|
4992
|
-
}] }, { type: undefined, decorators: [{
|
|
4993
|
-
type: Optional
|
|
4994
|
-
}, {
|
|
4995
|
-
type: Self
|
|
4996
|
-
}, {
|
|
4997
|
-
type: Inject,
|
|
4998
|
-
args: [NG_VALUE_ACCESSOR]
|
|
4999
|
-
}] }, { type: undefined, decorators: [{
|
|
5000
|
-
type: Optional
|
|
5001
|
-
}, {
|
|
5002
|
-
type: Inject,
|
|
5003
|
-
args: [NG_MODEL_WITH_FORM_CONTROL_WARNING]
|
|
5004
|
-
}] }, { type: undefined, decorators: [{
|
|
5005
|
-
type: Optional
|
|
5006
|
-
}, {
|
|
5007
|
-
type: Inject,
|
|
5008
|
-
args: [CALL_SET_DISABLED_STATE]
|
|
5009
|
-
}] }], propDecorators: { form: [{
|
|
5010
|
-
type: Input,
|
|
5011
|
-
args: ['formControl']
|
|
5012
|
-
}], isDisabled: [{
|
|
5013
|
-
type: Input,
|
|
5014
|
-
args: ['disabled']
|
|
5015
|
-
}], model: [{
|
|
5016
|
-
type: Input,
|
|
5017
|
-
args: ['ngModel']
|
|
5018
|
-
}], update: [{
|
|
5019
|
-
type: Output,
|
|
5020
|
-
args: ['ngModelChange']
|
|
5021
|
-
}] } });
|
|
5022
|
-
|
|
5023
|
-
const formDirectiveProvider = {
|
|
5024
|
-
provide: ControlContainer,
|
|
5025
|
-
useExisting: forwardRef(() => FormGroupDirective),
|
|
5026
|
-
};
|
|
5027
|
-
/**
|
|
5028
|
-
* @description
|
|
5029
|
-
*
|
|
5030
|
-
* Binds an existing `FormGroup` or `FormRecord` to a DOM element.
|
|
5031
|
-
*
|
|
5032
|
-
* This directive accepts an existing `FormGroup` instance. It will then use this
|
|
5033
|
-
* `FormGroup` instance to match any child `FormControl`, `FormGroup`/`FormRecord`,
|
|
5034
|
-
* and `FormArray` instances to child `FormControlName`, `FormGroupName`,
|
|
5035
|
-
* and `FormArrayName` directives.
|
|
5036
|
-
*
|
|
5037
|
-
* @see [Reactive Forms Guide](guide/forms/reactive-forms)
|
|
5038
|
-
* @see {@link AbstractControl}
|
|
5039
|
-
*
|
|
5040
|
-
* @usageNotes
|
|
5041
|
-
* ### Register Form Group
|
|
5042
|
-
*
|
|
5043
|
-
* The following example registers a `FormGroup` with first name and last name controls,
|
|
5044
|
-
* and listens for the *ngSubmit* event when the button is clicked.
|
|
5045
|
-
*
|
|
5046
|
-
* {@example forms/ts/simpleFormGroup/simple_form_group_example.ts region='Component'}
|
|
5047
|
-
*
|
|
5048
|
-
* @ngModule ReactiveFormsModule
|
|
5049
|
-
* @publicApi
|
|
5050
|
-
*/
|
|
5051
|
-
class FormGroupDirective extends ControlContainer {
|
|
5052
|
-
callSetDisabledState;
|
|
5053
|
-
/**
|
|
5054
|
-
* @description
|
|
5055
|
-
* Reports whether the form submission has been triggered.
|
|
5056
|
-
*/
|
|
5057
|
-
get submitted() {
|
|
5058
|
-
return untracked(this._submittedReactive);
|
|
5059
|
-
}
|
|
5060
|
-
// TODO(atscott): Remove once invalid API usage is cleaned up internally
|
|
5061
|
-
set submitted(value) {
|
|
5062
|
-
this._submittedReactive.set(value);
|
|
5063
|
-
}
|
|
5064
|
-
/** @internal */
|
|
5065
|
-
_submitted = computed(() => this._submittedReactive(), ...(ngDevMode ? [{ debugName: "_submitted" }] : []));
|
|
5066
|
-
_submittedReactive = signal(false, ...(ngDevMode ? [{ debugName: "_submittedReactive" }] : []));
|
|
5067
|
-
/**
|
|
5068
|
-
* Reference to an old form group input value, which is needed to cleanup
|
|
5069
|
-
* old instance in case it was replaced with a new one.
|
|
5070
|
-
*/
|
|
5071
|
-
_oldForm;
|
|
5072
|
-
/**
|
|
5073
|
-
* Callback that should be invoked when controls in FormGroup or FormArray collection change
|
|
5074
|
-
* (added or removed). This callback triggers corresponding DOM updates.
|
|
5075
|
-
*/
|
|
5076
|
-
_onCollectionChange = () => this._updateDomValue();
|
|
5077
|
-
/**
|
|
5078
|
-
* @description
|
|
5079
|
-
* Tracks the list of added `FormControlName` instances
|
|
5080
|
-
*/
|
|
5081
|
-
directives = [];
|
|
5082
|
-
/**
|
|
5083
|
-
* @description
|
|
5084
|
-
* Tracks the `FormGroup` bound to this directive.
|
|
5085
|
-
*/
|
|
5086
|
-
form = null;
|
|
5087
|
-
/**
|
|
5088
|
-
* @description
|
|
5089
|
-
* Emits an event when the form submission has been triggered.
|
|
5090
|
-
*/
|
|
5091
|
-
ngSubmit = new EventEmitter();
|
|
5092
|
-
constructor(validators, asyncValidators, callSetDisabledState) {
|
|
5093
|
-
super();
|
|
5094
|
-
this.callSetDisabledState = callSetDisabledState;
|
|
5095
|
-
this._setValidators(validators);
|
|
5096
|
-
this._setAsyncValidators(asyncValidators);
|
|
5097
|
-
}
|
|
5098
|
-
/** @docs-private */
|
|
5099
|
-
ngOnChanges(changes) {
|
|
5100
|
-
if ((typeof ngDevMode === 'undefined' || ngDevMode) && !this.form) {
|
|
5101
|
-
throw missingFormException();
|
|
5102
|
-
}
|
|
5103
|
-
if (changes.hasOwnProperty('form')) {
|
|
5104
|
-
this._updateValidators();
|
|
5105
|
-
this._updateDomValue();
|
|
5106
|
-
this._updateRegistrations();
|
|
5107
|
-
this._oldForm = this.form;
|
|
5108
|
-
}
|
|
5109
|
-
}
|
|
5110
|
-
/** @docs-private */
|
|
5111
|
-
ngOnDestroy() {
|
|
5112
|
-
if (this.form) {
|
|
5113
|
-
cleanUpValidators(this.form, this);
|
|
5114
|
-
// Currently the `onCollectionChange` callback is rewritten each time the
|
|
5115
|
-
// `_registerOnCollectionChange` function is invoked. The implication is that cleanup should
|
|
5116
|
-
// happen *only* when the `onCollectionChange` callback was set by this directive instance.
|
|
5117
|
-
// Otherwise it might cause overriding a callback of some other directive instances. We should
|
|
5118
|
-
// consider updating this logic later to make it similar to how `onChange` callbacks are
|
|
5119
|
-
// handled, see https://github.com/angular/angular/issues/39732 for additional info.
|
|
5120
|
-
if (this.form._onCollectionChange === this._onCollectionChange) {
|
|
5121
|
-
this.form._registerOnCollectionChange(() => { });
|
|
5122
|
-
}
|
|
5019
|
+
setControl(index, control, options = {}) {
|
|
5020
|
+
// Adjust the index, then clamp it at no less than 0 to prevent undesired underflows.
|
|
5021
|
+
let adjustedIndex = this._adjustIndex(index);
|
|
5022
|
+
if (adjustedIndex < 0)
|
|
5023
|
+
adjustedIndex = 0;
|
|
5024
|
+
if (this.controls[adjustedIndex])
|
|
5025
|
+
this.controls[adjustedIndex]._registerOnCollectionChange(() => { });
|
|
5026
|
+
this.controls.splice(adjustedIndex, 1);
|
|
5027
|
+
if (control) {
|
|
5028
|
+
this.controls.splice(adjustedIndex, 0, control);
|
|
5029
|
+
this._registerControl(control);
|
|
5123
5030
|
}
|
|
5031
|
+
this.updateValueAndValidity({ emitEvent: options.emitEvent });
|
|
5032
|
+
this._onCollectionChange();
|
|
5124
5033
|
}
|
|
5125
5034
|
/**
|
|
5126
|
-
*
|
|
5127
|
-
* Returns this directive's instance.
|
|
5128
|
-
*/
|
|
5129
|
-
get formDirective() {
|
|
5130
|
-
return this;
|
|
5131
|
-
}
|
|
5132
|
-
/**
|
|
5133
|
-
* @description
|
|
5134
|
-
* Returns the `FormGroup` bound to this directive.
|
|
5135
|
-
*/
|
|
5136
|
-
get control() {
|
|
5137
|
-
return this.form;
|
|
5138
|
-
}
|
|
5139
|
-
/**
|
|
5140
|
-
* @description
|
|
5141
|
-
* Returns an array representing the path to this group. Because this directive
|
|
5142
|
-
* always lives at the top level of a form, it always an empty array.
|
|
5035
|
+
* Length of the control array.
|
|
5143
5036
|
*/
|
|
5144
|
-
get
|
|
5145
|
-
return
|
|
5037
|
+
get length() {
|
|
5038
|
+
return this.controls.length;
|
|
5146
5039
|
}
|
|
5147
5040
|
/**
|
|
5148
|
-
*
|
|
5149
|
-
*
|
|
5150
|
-
* and validity, and adds the instance to the internal list of directives.
|
|
5041
|
+
* Sets the value of the `FormArray`. It accepts an array that matches
|
|
5042
|
+
* the structure of the control.
|
|
5151
5043
|
*
|
|
5152
|
-
*
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
const ctrl = this.form.get(dir.path);
|
|
5156
|
-
setUpControl(ctrl, dir, this.callSetDisabledState);
|
|
5157
|
-
ctrl.updateValueAndValidity({ emitEvent: false });
|
|
5158
|
-
this.directives.push(dir);
|
|
5159
|
-
return ctrl;
|
|
5160
|
-
}
|
|
5161
|
-
/**
|
|
5162
|
-
* @description
|
|
5163
|
-
* Retrieves the `FormControl` instance from the provided `FormControlName` directive
|
|
5044
|
+
* This method performs strict checks, and throws an error if you try
|
|
5045
|
+
* to set the value of a control that doesn't exist or if you exclude the
|
|
5046
|
+
* value of a control.
|
|
5164
5047
|
*
|
|
5165
|
-
* @
|
|
5166
|
-
|
|
5167
|
-
getControl(dir) {
|
|
5168
|
-
return this.form.get(dir.path);
|
|
5169
|
-
}
|
|
5170
|
-
/**
|
|
5171
|
-
* @description
|
|
5172
|
-
* Removes the `FormControlName` instance from the internal list of directives
|
|
5048
|
+
* @usageNotes
|
|
5049
|
+
* ### Set the values for the controls in the form array
|
|
5173
5050
|
*
|
|
5174
|
-
*
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
/**
|
|
5181
|
-
* Adds a new `FormGroupName` directive instance to the form.
|
|
5051
|
+
* ```ts
|
|
5052
|
+
* const arr = new FormArray([
|
|
5053
|
+
* new FormControl(),
|
|
5054
|
+
* new FormControl()
|
|
5055
|
+
* ]);
|
|
5056
|
+
* console.log(arr.value); // [null, null]
|
|
5182
5057
|
*
|
|
5183
|
-
*
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
this._setUpFormContainer(dir);
|
|
5187
|
-
}
|
|
5188
|
-
/**
|
|
5189
|
-
* Performs the necessary cleanup when a `FormGroupName` directive instance is removed from the
|
|
5190
|
-
* view.
|
|
5058
|
+
* arr.setValue(['Nancy', 'Drew']);
|
|
5059
|
+
* console.log(arr.value); // ['Nancy', 'Drew']
|
|
5060
|
+
* ```
|
|
5191
5061
|
*
|
|
5192
|
-
* @param
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
this._cleanUpFormContainer(dir);
|
|
5196
|
-
}
|
|
5197
|
-
/**
|
|
5198
|
-
* @description
|
|
5199
|
-
* Retrieves the `FormGroup` for a provided `FormGroupName` directive instance
|
|
5062
|
+
* @param value Array of values for the controls
|
|
5063
|
+
* @param options Configure options that determine how the control propagates changes and
|
|
5064
|
+
* emits events after the value changes
|
|
5200
5065
|
*
|
|
5201
|
-
*
|
|
5066
|
+
* * `onlySelf`: When true, each change only affects this control, and not its parent. Default
|
|
5067
|
+
* is false.
|
|
5068
|
+
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
|
5069
|
+
* `valueChanges`
|
|
5070
|
+
* observables emit events with the latest status and value when the control value is updated.
|
|
5071
|
+
* When false, no events are emitted.
|
|
5072
|
+
* The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
|
|
5073
|
+
* updateValueAndValidity} method.
|
|
5202
5074
|
*/
|
|
5203
|
-
|
|
5204
|
-
|
|
5075
|
+
setValue(value, options = {}) {
|
|
5076
|
+
assertAllValuesPresent(this, false, value);
|
|
5077
|
+
value.forEach((newValue, index) => {
|
|
5078
|
+
assertControlPresent(this, false, index);
|
|
5079
|
+
this.at(index).setValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
|
|
5080
|
+
});
|
|
5081
|
+
this.updateValueAndValidity(options);
|
|
5205
5082
|
}
|
|
5206
5083
|
/**
|
|
5207
|
-
*
|
|
5084
|
+
* Patches the value of the `FormArray`. It accepts an array that matches the
|
|
5085
|
+
* structure of the control, and does its best to match the values to the correct
|
|
5086
|
+
* controls in the group.
|
|
5208
5087
|
*
|
|
5209
|
-
*
|
|
5210
|
-
*/
|
|
5211
|
-
addFormArray(dir) {
|
|
5212
|
-
this._setUpFormContainer(dir);
|
|
5213
|
-
}
|
|
5214
|
-
/**
|
|
5215
|
-
* Performs the necessary cleanup when a `FormArrayName` directive instance is removed from the
|
|
5216
|
-
* view.
|
|
5088
|
+
* It accepts both super-sets and sub-sets of the array without throwing an error.
|
|
5217
5089
|
*
|
|
5218
|
-
* @
|
|
5090
|
+
* @usageNotes
|
|
5091
|
+
* ### Patch the values for controls in a form array
|
|
5092
|
+
*
|
|
5093
|
+
* ```ts
|
|
5094
|
+
* const arr = new FormArray([
|
|
5095
|
+
* new FormControl(),
|
|
5096
|
+
* new FormControl()
|
|
5097
|
+
* ]);
|
|
5098
|
+
* console.log(arr.value); // [null, null]
|
|
5099
|
+
*
|
|
5100
|
+
* arr.patchValue(['Nancy']);
|
|
5101
|
+
* console.log(arr.value); // ['Nancy', null]
|
|
5102
|
+
* ```
|
|
5103
|
+
*
|
|
5104
|
+
* @param value Array of latest values for the controls
|
|
5105
|
+
* @param options Configure options that determine how the control propagates changes and
|
|
5106
|
+
* emits events after the value changes
|
|
5107
|
+
*
|
|
5108
|
+
* * `onlySelf`: When true, each change only affects this control, and not its parent. Default
|
|
5109
|
+
* is false.
|
|
5110
|
+
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
|
5111
|
+
* `valueChanges` observables emit events with the latest status and value when the control
|
|
5112
|
+
* value is updated. When false, no events are emitted. The configuration options are passed to
|
|
5113
|
+
* the {@link AbstractControl#updateValueAndValidity updateValueAndValidity} method.
|
|
5219
5114
|
*/
|
|
5220
|
-
|
|
5221
|
-
|
|
5115
|
+
patchValue(value, options = {}) {
|
|
5116
|
+
// Even though the `value` argument type doesn't allow `null` and `undefined` values, the
|
|
5117
|
+
// `patchValue` can be called recursively and inner data structures might have these values,
|
|
5118
|
+
// so we just ignore such cases when a field containing FormArray instance receives `null` or
|
|
5119
|
+
// `undefined` as a value.
|
|
5120
|
+
if (value == null /* both `null` and `undefined` */)
|
|
5121
|
+
return;
|
|
5122
|
+
value.forEach((newValue, index) => {
|
|
5123
|
+
if (this.at(index)) {
|
|
5124
|
+
this.at(index).patchValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
|
|
5125
|
+
}
|
|
5126
|
+
});
|
|
5127
|
+
this.updateValueAndValidity(options);
|
|
5222
5128
|
}
|
|
5223
5129
|
/**
|
|
5224
|
-
*
|
|
5225
|
-
*
|
|
5130
|
+
* Resets the `FormArray` and all descendants are marked `pristine` and `untouched`, and the
|
|
5131
|
+
* value of all descendants to null or null maps.
|
|
5226
5132
|
*
|
|
5227
|
-
*
|
|
5133
|
+
* You reset to a specific form state by passing in an array of states
|
|
5134
|
+
* that matches the structure of the control. The state is a standalone value
|
|
5135
|
+
* or a form state object with both a value and a disabled status.
|
|
5136
|
+
*
|
|
5137
|
+
* @usageNotes
|
|
5138
|
+
* ### Reset the values in a form array
|
|
5139
|
+
*
|
|
5140
|
+
* ```ts
|
|
5141
|
+
* const arr = new FormArray([
|
|
5142
|
+
* new FormControl(),
|
|
5143
|
+
* new FormControl()
|
|
5144
|
+
* ]);
|
|
5145
|
+
* arr.reset(['name', 'last name']);
|
|
5146
|
+
*
|
|
5147
|
+
* console.log(arr.value); // ['name', 'last name']
|
|
5148
|
+
* ```
|
|
5149
|
+
*
|
|
5150
|
+
* ### Reset the values in a form array and the disabled status for the first control
|
|
5151
|
+
*
|
|
5152
|
+
* ```ts
|
|
5153
|
+
* arr.reset([
|
|
5154
|
+
* {value: 'name', disabled: true},
|
|
5155
|
+
* 'last'
|
|
5156
|
+
* ]);
|
|
5157
|
+
*
|
|
5158
|
+
* console.log(arr.value); // ['last']
|
|
5159
|
+
* console.log(arr.at(0).status); // 'DISABLED'
|
|
5160
|
+
* ```
|
|
5161
|
+
*
|
|
5162
|
+
* @param value Array of values for the controls
|
|
5163
|
+
* @param options Configure options that determine how the control propagates changes and
|
|
5164
|
+
* emits events after the value changes
|
|
5165
|
+
*
|
|
5166
|
+
* * `onlySelf`: When true, each change only affects this control, and not its parent. Default
|
|
5167
|
+
* is false.
|
|
5168
|
+
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
|
5169
|
+
* `valueChanges`
|
|
5170
|
+
* observables emit events with the latest status and value when the control is reset.
|
|
5171
|
+
* When false, no events are emitted.
|
|
5172
|
+
* The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
|
|
5173
|
+
* updateValueAndValidity} method.
|
|
5228
5174
|
*/
|
|
5229
|
-
|
|
5230
|
-
|
|
5175
|
+
reset(value = [], options = {}) {
|
|
5176
|
+
this._forEachChild((control, index) => {
|
|
5177
|
+
control.reset(value[index], { onlySelf: true, emitEvent: options.emitEvent });
|
|
5178
|
+
});
|
|
5179
|
+
this._updatePristine(options, this);
|
|
5180
|
+
this._updateTouched(options, this);
|
|
5181
|
+
this.updateValueAndValidity(options);
|
|
5231
5182
|
}
|
|
5232
5183
|
/**
|
|
5233
|
-
*
|
|
5184
|
+
* The aggregate value of the array, including any disabled controls.
|
|
5234
5185
|
*
|
|
5235
|
-
*
|
|
5236
|
-
* @param value The new value for the directive's control.
|
|
5186
|
+
* Reports all values regardless of disabled status.
|
|
5237
5187
|
*/
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
ctrl.setValue(value);
|
|
5188
|
+
getRawValue() {
|
|
5189
|
+
return this.controls.map((control) => control.getRawValue());
|
|
5241
5190
|
}
|
|
5242
5191
|
/**
|
|
5243
|
-
*
|
|
5244
|
-
* Method called with the "submit" event is triggered on the form.
|
|
5245
|
-
* Triggers the `ngSubmit` emitter to emit the "submit" event as its payload.
|
|
5192
|
+
* Remove all controls in the `FormArray`.
|
|
5246
5193
|
*
|
|
5247
|
-
* @param
|
|
5194
|
+
* @param options Specifies whether this FormArray instance should emit events after all
|
|
5195
|
+
* controls are removed.
|
|
5196
|
+
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
|
5197
|
+
* `valueChanges` observables emit events with the latest status and value when all controls
|
|
5198
|
+
* in this FormArray instance are removed. When false, no events are emitted.
|
|
5199
|
+
*
|
|
5200
|
+
* @usageNotes
|
|
5201
|
+
* ### Remove all elements from a FormArray
|
|
5202
|
+
*
|
|
5203
|
+
* ```ts
|
|
5204
|
+
* const arr = new FormArray([
|
|
5205
|
+
* new FormControl(),
|
|
5206
|
+
* new FormControl()
|
|
5207
|
+
* ]);
|
|
5208
|
+
* console.log(arr.length); // 2
|
|
5209
|
+
*
|
|
5210
|
+
* arr.clear();
|
|
5211
|
+
* console.log(arr.length); // 0
|
|
5212
|
+
* ```
|
|
5213
|
+
*
|
|
5214
|
+
* It's a simpler and more efficient alternative to removing all elements one by one:
|
|
5215
|
+
*
|
|
5216
|
+
* ```ts
|
|
5217
|
+
* const arr = new FormArray([
|
|
5218
|
+
* new FormControl(),
|
|
5219
|
+
* new FormControl()
|
|
5220
|
+
* ]);
|
|
5221
|
+
*
|
|
5222
|
+
* while (arr.length) {
|
|
5223
|
+
* arr.removeAt(0);
|
|
5224
|
+
* }
|
|
5225
|
+
* ```
|
|
5248
5226
|
*/
|
|
5249
|
-
|
|
5250
|
-
this.
|
|
5251
|
-
|
|
5252
|
-
this.
|
|
5253
|
-
this.
|
|
5254
|
-
|
|
5255
|
-
// shouldn't be prevented. Note that we need to null check the `event` and the `target`, because
|
|
5256
|
-
// some internal apps call this method directly with the wrong arguments.
|
|
5257
|
-
return $event?.target?.method === 'dialog';
|
|
5227
|
+
clear(options = {}) {
|
|
5228
|
+
if (this.controls.length < 1)
|
|
5229
|
+
return;
|
|
5230
|
+
this._forEachChild((control) => control._registerOnCollectionChange(() => { }));
|
|
5231
|
+
this.controls.splice(0);
|
|
5232
|
+
this.updateValueAndValidity({ emitEvent: options.emitEvent });
|
|
5258
5233
|
}
|
|
5259
5234
|
/**
|
|
5260
|
-
*
|
|
5261
|
-
*
|
|
5235
|
+
* Adjusts a negative index by summing it with the length of the array. For very negative
|
|
5236
|
+
* indices, the result may remain negative.
|
|
5237
|
+
* @internal
|
|
5262
5238
|
*/
|
|
5263
|
-
|
|
5264
|
-
this.
|
|
5239
|
+
_adjustIndex(index) {
|
|
5240
|
+
return index < 0 ? index + this.length : index;
|
|
5265
5241
|
}
|
|
5266
|
-
/**
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
this._submittedReactive.set(false);
|
|
5275
|
-
if (options?.emitEvent !== false) {
|
|
5276
|
-
this.form._events.next(new FormResetEvent(this.form));
|
|
5277
|
-
}
|
|
5242
|
+
/** @internal */
|
|
5243
|
+
_syncPendingControls() {
|
|
5244
|
+
let subtreeUpdated = this.controls.reduce((updated, child) => {
|
|
5245
|
+
return child._syncPendingControls() ? true : updated;
|
|
5246
|
+
}, false);
|
|
5247
|
+
if (subtreeUpdated)
|
|
5248
|
+
this.updateValueAndValidity({ onlySelf: true });
|
|
5249
|
+
return subtreeUpdated;
|
|
5278
5250
|
}
|
|
5279
5251
|
/** @internal */
|
|
5280
|
-
|
|
5281
|
-
this.
|
|
5282
|
-
|
|
5283
|
-
const newCtrl = this.form.get(dir.path);
|
|
5284
|
-
if (oldCtrl !== newCtrl) {
|
|
5285
|
-
// Note: the value of the `dir.control` may not be defined, for example when it's a first
|
|
5286
|
-
// `FormControl` that is added to a `FormGroup` instance (via `addControl` call).
|
|
5287
|
-
cleanUpControl(oldCtrl || null, dir);
|
|
5288
|
-
// Check whether new control at the same location inside the corresponding `FormGroup` is an
|
|
5289
|
-
// instance of `FormControl` and perform control setup only if that's the case.
|
|
5290
|
-
// Note: we don't need to clear the list of directives (`this.directives`) here, it would be
|
|
5291
|
-
// taken care of in the `removeControl` method invoked when corresponding `formControlName`
|
|
5292
|
-
// directive instance is being removed (invoked from `FormControlName.ngOnDestroy`).
|
|
5293
|
-
if (isFormControl(newCtrl)) {
|
|
5294
|
-
setUpControl(newCtrl, dir, this.callSetDisabledState);
|
|
5295
|
-
dir.control = newCtrl;
|
|
5296
|
-
}
|
|
5297
|
-
}
|
|
5252
|
+
_forEachChild(cb) {
|
|
5253
|
+
this.controls.forEach((control, index) => {
|
|
5254
|
+
cb(control, index);
|
|
5298
5255
|
});
|
|
5299
|
-
this.form._updateTreeValidity({ emitEvent: false });
|
|
5300
5256
|
}
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
// `_cleanUpFormContainer` function.
|
|
5307
|
-
ctrl.updateValueAndValidity({ emitEvent: false });
|
|
5257
|
+
/** @internal */
|
|
5258
|
+
_updateValue() {
|
|
5259
|
+
this.value = this.controls
|
|
5260
|
+
.filter((control) => control.enabled || this.disabled)
|
|
5261
|
+
.map((control) => control.value);
|
|
5308
5262
|
}
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
if (ctrl) {
|
|
5313
|
-
const isControlUpdated = cleanUpFormContainer(ctrl, dir);
|
|
5314
|
-
if (isControlUpdated) {
|
|
5315
|
-
// Run validity check only in case a control was updated (i.e. view validators were
|
|
5316
|
-
// removed) as removing view validators might cause validity to change.
|
|
5317
|
-
ctrl.updateValueAndValidity({ emitEvent: false });
|
|
5318
|
-
}
|
|
5319
|
-
}
|
|
5320
|
-
}
|
|
5263
|
+
/** @internal */
|
|
5264
|
+
_anyControls(condition) {
|
|
5265
|
+
return this.controls.some((control) => control.enabled && condition(control));
|
|
5321
5266
|
}
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
this._oldForm._registerOnCollectionChange(() => { });
|
|
5326
|
-
}
|
|
5267
|
+
/** @internal */
|
|
5268
|
+
_setUpControls() {
|
|
5269
|
+
this._forEachChild((control) => this._registerControl(control));
|
|
5327
5270
|
}
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5271
|
+
/** @internal */
|
|
5272
|
+
_allControlsDisabled() {
|
|
5273
|
+
for (const control of this.controls) {
|
|
5274
|
+
if (control.enabled)
|
|
5275
|
+
return false;
|
|
5332
5276
|
}
|
|
5277
|
+
return this.controls.length > 0 || this.disabled;
|
|
5278
|
+
}
|
|
5279
|
+
_registerControl(control) {
|
|
5280
|
+
control.setParent(this);
|
|
5281
|
+
control._registerOnCollectionChange(this._onCollectionChange);
|
|
5282
|
+
}
|
|
5283
|
+
/** @internal */
|
|
5284
|
+
_find(name) {
|
|
5285
|
+
return this.at(name) ?? null;
|
|
5333
5286
|
}
|
|
5334
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormGroupDirective, deps: [{ token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: CALL_SET_DISABLED_STATE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
5335
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: FormGroupDirective, isStandalone: false, selector: "[formGroup]", inputs: { form: ["formGroup", "form"] }, outputs: { ngSubmit: "ngSubmit" }, host: { listeners: { "submit": "onSubmit($event)", "reset": "onReset()" } }, providers: [formDirectiveProvider], exportAs: ["ngForm"], usesInheritance: true, usesOnChanges: true, ngImport: i0 });
|
|
5336
5287
|
}
|
|
5337
|
-
|
|
5338
|
-
type: Directive,
|
|
5339
|
-
args: [{
|
|
5340
|
-
selector: '[formGroup]',
|
|
5341
|
-
providers: [formDirectiveProvider],
|
|
5342
|
-
host: { '(submit)': 'onSubmit($event)', '(reset)': 'onReset()' },
|
|
5343
|
-
exportAs: 'ngForm',
|
|
5344
|
-
standalone: false,
|
|
5345
|
-
}]
|
|
5346
|
-
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
5347
|
-
type: Optional
|
|
5348
|
-
}, {
|
|
5349
|
-
type: Self
|
|
5350
|
-
}, {
|
|
5351
|
-
type: Inject,
|
|
5352
|
-
args: [NG_VALIDATORS]
|
|
5353
|
-
}] }, { type: undefined, decorators: [{
|
|
5354
|
-
type: Optional
|
|
5355
|
-
}, {
|
|
5356
|
-
type: Self
|
|
5357
|
-
}, {
|
|
5358
|
-
type: Inject,
|
|
5359
|
-
args: [NG_ASYNC_VALIDATORS]
|
|
5360
|
-
}] }, { type: undefined, decorators: [{
|
|
5361
|
-
type: Optional
|
|
5362
|
-
}, {
|
|
5363
|
-
type: Inject,
|
|
5364
|
-
args: [CALL_SET_DISABLED_STATE]
|
|
5365
|
-
}] }], propDecorators: { form: [{
|
|
5366
|
-
type: Input,
|
|
5367
|
-
args: ['formGroup']
|
|
5368
|
-
}], ngSubmit: [{
|
|
5369
|
-
type: Output
|
|
5370
|
-
}] } });
|
|
5371
|
-
|
|
5372
|
-
const formGroupNameProvider = {
|
|
5373
|
-
provide: ControlContainer,
|
|
5374
|
-
useExisting: forwardRef(() => FormGroupName),
|
|
5375
|
-
};
|
|
5288
|
+
const UntypedFormArray = FormArray;
|
|
5376
5289
|
/**
|
|
5377
5290
|
* @description
|
|
5291
|
+
* Asserts that the given control is an instance of `FormArray`
|
|
5378
5292
|
*
|
|
5379
|
-
* Syncs a nested `FormGroup` or `FormRecord` to a DOM element.
|
|
5380
|
-
*
|
|
5381
|
-
* This directive can only be used with a parent `FormGroupDirective`.
|
|
5382
|
-
*
|
|
5383
|
-
* It accepts the string name of the nested `FormGroup` or `FormRecord` to link, and
|
|
5384
|
-
* looks for a `FormGroup` or `FormRecord` registered with that name in the parent
|
|
5385
|
-
* `FormGroup` instance you passed into `FormGroupDirective`.
|
|
5386
|
-
*
|
|
5387
|
-
* Use nested form groups to validate a sub-group of a
|
|
5388
|
-
* form separately from the rest or to group the values of certain
|
|
5389
|
-
* controls into their own nested object.
|
|
5390
|
-
*
|
|
5391
|
-
* @see [Reactive Forms Guide](guide/forms/reactive-forms)
|
|
5392
|
-
*
|
|
5393
|
-
* @usageNotes
|
|
5394
|
-
*
|
|
5395
|
-
* ### Access the group by name
|
|
5396
|
-
*
|
|
5397
|
-
* The following example uses the `AbstractControl.get` method to access the
|
|
5398
|
-
* associated `FormGroup`
|
|
5399
|
-
*
|
|
5400
|
-
* ```ts
|
|
5401
|
-
* this.form.get('name');
|
|
5402
|
-
* ```
|
|
5403
|
-
*
|
|
5404
|
-
* ### Access individual controls in the group
|
|
5405
|
-
*
|
|
5406
|
-
* The following example uses the `AbstractControl.get` method to access
|
|
5407
|
-
* individual controls within the group using dot syntax.
|
|
5408
|
-
*
|
|
5409
|
-
* ```ts
|
|
5410
|
-
* this.form.get('name.first');
|
|
5411
|
-
* ```
|
|
5412
|
-
*
|
|
5413
|
-
* ### Register a nested `FormGroup`.
|
|
5414
|
-
*
|
|
5415
|
-
* The following example registers a nested *name* `FormGroup` within an existing `FormGroup`,
|
|
5416
|
-
* and provides methods to retrieve the nested `FormGroup` and individual controls.
|
|
5417
|
-
*
|
|
5418
|
-
* {@example forms/ts/nestedFormGroup/nested_form_group_example.ts region='Component'}
|
|
5419
|
-
*
|
|
5420
|
-
* @ngModule ReactiveFormsModule
|
|
5421
5293
|
* @publicApi
|
|
5422
5294
|
*/
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
* @description
|
|
5426
|
-
* Tracks the name of the `FormGroup` bound to the directive. The name corresponds
|
|
5427
|
-
* to a key in the parent `FormGroup` or `FormArray`.
|
|
5428
|
-
* Accepts a name as a string or a number.
|
|
5429
|
-
* The name in the form of a string is useful for individual forms,
|
|
5430
|
-
* while the numerical form allows for form groups to be bound
|
|
5431
|
-
* to indices when iterating over groups in a `FormArray`.
|
|
5432
|
-
*/
|
|
5433
|
-
name = null;
|
|
5434
|
-
constructor(parent, validators, asyncValidators) {
|
|
5435
|
-
super();
|
|
5436
|
-
this._parent = parent;
|
|
5437
|
-
this._setValidators(validators);
|
|
5438
|
-
this._setAsyncValidators(asyncValidators);
|
|
5439
|
-
}
|
|
5440
|
-
/** @internal */
|
|
5441
|
-
_checkParentType() {
|
|
5442
|
-
if (hasInvalidParent(this._parent) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
5443
|
-
throw groupParentException();
|
|
5444
|
-
}
|
|
5445
|
-
}
|
|
5446
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormGroupName, deps: [{ token: ControlContainer, host: true, optional: true, skipSelf: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
5447
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: FormGroupName, isStandalone: false, selector: "[formGroupName]", inputs: { name: ["formGroupName", "name"] }, providers: [formGroupNameProvider], usesInheritance: true, ngImport: i0 });
|
|
5448
|
-
}
|
|
5449
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormGroupName, decorators: [{
|
|
5450
|
-
type: Directive,
|
|
5451
|
-
args: [{
|
|
5452
|
-
selector: '[formGroupName]',
|
|
5453
|
-
providers: [formGroupNameProvider],
|
|
5454
|
-
standalone: false,
|
|
5455
|
-
}]
|
|
5456
|
-
}], ctorParameters: () => [{ type: ControlContainer, decorators: [{
|
|
5457
|
-
type: Optional
|
|
5458
|
-
}, {
|
|
5459
|
-
type: Host
|
|
5460
|
-
}, {
|
|
5461
|
-
type: SkipSelf
|
|
5462
|
-
}] }, { type: undefined, decorators: [{
|
|
5463
|
-
type: Optional
|
|
5464
|
-
}, {
|
|
5465
|
-
type: Self
|
|
5466
|
-
}, {
|
|
5467
|
-
type: Inject,
|
|
5468
|
-
args: [NG_VALIDATORS]
|
|
5469
|
-
}] }, { type: undefined, decorators: [{
|
|
5470
|
-
type: Optional
|
|
5471
|
-
}, {
|
|
5472
|
-
type: Self
|
|
5473
|
-
}, {
|
|
5474
|
-
type: Inject,
|
|
5475
|
-
args: [NG_ASYNC_VALIDATORS]
|
|
5476
|
-
}] }], propDecorators: { name: [{
|
|
5477
|
-
type: Input,
|
|
5478
|
-
args: ['formGroupName']
|
|
5479
|
-
}] } });
|
|
5480
|
-
const formArrayNameProvider = {
|
|
5481
|
-
provide: ControlContainer,
|
|
5482
|
-
useExisting: forwardRef(() => FormArrayName),
|
|
5483
|
-
};
|
|
5295
|
+
const isFormArray = (control) => control instanceof FormArray;
|
|
5296
|
+
|
|
5484
5297
|
/**
|
|
5485
5298
|
* @description
|
|
5486
5299
|
*
|
|
5487
|
-
*
|
|
5488
|
-
*
|
|
5489
|
-
* This directive is designed to be used with a parent `FormGroupDirective` (selector:
|
|
5490
|
-
* `[formGroup]`).
|
|
5491
|
-
*
|
|
5492
|
-
* It accepts the string name of the nested `FormArray` you want to link, and
|
|
5493
|
-
* will look for a `FormArray` registered with that name in the parent
|
|
5494
|
-
* `FormGroup` instance you passed into `FormGroupDirective`.
|
|
5495
|
-
*
|
|
5496
|
-
* @see [Reactive Forms Guide](guide/forms/reactive-forms)
|
|
5497
|
-
* @see {@link AbstractControl}
|
|
5498
|
-
*
|
|
5499
|
-
* @usageNotes
|
|
5500
|
-
*
|
|
5501
|
-
* ### Example
|
|
5502
|
-
*
|
|
5503
|
-
* {@example forms/ts/nestedFormArray/nested_form_array_example.ts region='Component'}
|
|
5300
|
+
* Abstract class for top-level form directives (FormArrayDirective, FormGroupDirective) who bind an
|
|
5301
|
+
* existing `Form` to a DOM element.
|
|
5504
5302
|
*
|
|
5505
|
-
* @ngModule ReactiveFormsModule
|
|
5506
5303
|
* @publicApi
|
|
5507
5304
|
*/
|
|
5508
|
-
class
|
|
5509
|
-
|
|
5510
|
-
_parent;
|
|
5305
|
+
class AbstractFormDirective extends ControlContainer {
|
|
5306
|
+
callSetDisabledState;
|
|
5511
5307
|
/**
|
|
5512
5308
|
* @description
|
|
5513
|
-
*
|
|
5514
|
-
* to a key in the parent `FormGroup` or `FormArray`.
|
|
5515
|
-
* Accepts a name as a string or a number.
|
|
5516
|
-
* The name in the form of a string is useful for individual forms,
|
|
5517
|
-
* while the numerical form allows for form arrays to be bound
|
|
5518
|
-
* to indices when iterating over arrays in a `FormArray`.
|
|
5309
|
+
* Reports whether the form submission has been triggered.
|
|
5519
5310
|
*/
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
super();
|
|
5523
|
-
this._parent = parent;
|
|
5524
|
-
this._setValidators(validators);
|
|
5525
|
-
this._setAsyncValidators(asyncValidators);
|
|
5311
|
+
get submitted() {
|
|
5312
|
+
return untracked(this._submittedReactive);
|
|
5526
5313
|
}
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
* @docs-private
|
|
5531
|
-
*/
|
|
5532
|
-
ngOnInit() {
|
|
5533
|
-
if (hasInvalidParent(this._parent) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
5534
|
-
throw arrayParentException();
|
|
5535
|
-
}
|
|
5536
|
-
this.formDirective.addFormArray(this);
|
|
5314
|
+
// TODO(atscott): Remove once invalid API usage is cleaned up internally
|
|
5315
|
+
set submitted(value) {
|
|
5316
|
+
this._submittedReactive.set(value);
|
|
5537
5317
|
}
|
|
5318
|
+
/** @internal */
|
|
5319
|
+
_submitted = computed(() => this._submittedReactive(), ...(ngDevMode ? [{ debugName: "_submitted" }] : []));
|
|
5320
|
+
_submittedReactive = signal(false, ...(ngDevMode ? [{ debugName: "_submittedReactive" }] : []));
|
|
5538
5321
|
/**
|
|
5539
|
-
*
|
|
5540
|
-
*
|
|
5322
|
+
* Reference to an old form group input value, which is needed to cleanup
|
|
5323
|
+
* old instance in case it was replaced with a new one.
|
|
5541
5324
|
*/
|
|
5542
|
-
|
|
5543
|
-
this.formDirective?.removeFormArray(this);
|
|
5544
|
-
}
|
|
5325
|
+
_oldForm;
|
|
5545
5326
|
/**
|
|
5546
|
-
*
|
|
5547
|
-
*
|
|
5327
|
+
* Callback that should be invoked when controls in FormGroup or FormArray collection change
|
|
5328
|
+
* (added or removed). This callback triggers corresponding DOM updates.
|
|
5548
5329
|
*/
|
|
5549
|
-
|
|
5550
|
-
return this.formDirective.getFormArray(this);
|
|
5551
|
-
}
|
|
5330
|
+
_onCollectionChange = () => this._updateDomValue();
|
|
5552
5331
|
/**
|
|
5553
5332
|
* @description
|
|
5554
|
-
*
|
|
5333
|
+
* Tracks the list of added `FormControlName` instances
|
|
5555
5334
|
*/
|
|
5556
|
-
|
|
5557
|
-
|
|
5335
|
+
directives = [];
|
|
5336
|
+
constructor(validators, asyncValidators, callSetDisabledState) {
|
|
5337
|
+
super();
|
|
5338
|
+
this.callSetDisabledState = callSetDisabledState;
|
|
5339
|
+
this._setValidators(validators);
|
|
5340
|
+
this._setAsyncValidators(asyncValidators);
|
|
5558
5341
|
}
|
|
5559
|
-
/**
|
|
5342
|
+
/** @nodoc */
|
|
5343
|
+
ngOnChanges(changes) {
|
|
5344
|
+
this.onChanges(changes);
|
|
5345
|
+
}
|
|
5346
|
+
/** @nodoc */
|
|
5347
|
+
ngOnDestroy() {
|
|
5348
|
+
this.onDestroy();
|
|
5349
|
+
}
|
|
5350
|
+
/** @nodoc */
|
|
5351
|
+
onChanges(changes) {
|
|
5352
|
+
this._checkFormPresent();
|
|
5353
|
+
if (changes.hasOwnProperty('form')) {
|
|
5354
|
+
this._updateValidators();
|
|
5355
|
+
this._updateDomValue();
|
|
5356
|
+
this._updateRegistrations();
|
|
5357
|
+
this._oldForm = this.form;
|
|
5358
|
+
}
|
|
5359
|
+
}
|
|
5360
|
+
/** @nodoc */
|
|
5361
|
+
onDestroy() {
|
|
5362
|
+
if (this.form) {
|
|
5363
|
+
cleanUpValidators(this.form, this);
|
|
5364
|
+
// Currently the `onCollectionChange` callback is rewritten each time the
|
|
5365
|
+
// `_registerOnCollectionChange` function is invoked. The implication is that cleanup should
|
|
5366
|
+
// happen *only* when the `onCollectionChange` callback was set by this directive instance.
|
|
5367
|
+
// Otherwise it might cause overriding a callback of some other directive instances. We should
|
|
5368
|
+
// consider updating this logic later to make it similar to how `onChange` callbacks are
|
|
5369
|
+
// handled, see https://github.com/angular/angular/issues/39732 for additional info.
|
|
5370
|
+
if (this.form._onCollectionChange === this._onCollectionChange) {
|
|
5371
|
+
this.form._registerOnCollectionChange(() => { });
|
|
5372
|
+
}
|
|
5373
|
+
}
|
|
5374
|
+
}
|
|
5375
|
+
/**
|
|
5560
5376
|
* @description
|
|
5561
|
-
* Returns
|
|
5562
|
-
* Each index is the string name of the control on that level.
|
|
5377
|
+
* Returns this directive's instance.
|
|
5563
5378
|
*/
|
|
5564
|
-
get
|
|
5565
|
-
return
|
|
5379
|
+
get formDirective() {
|
|
5380
|
+
return this;
|
|
5566
5381
|
}
|
|
5567
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormArrayName, deps: [{ token: ControlContainer, host: true, optional: true, skipSelf: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
5568
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: FormArrayName, isStandalone: false, selector: "[formArrayName]", inputs: { name: ["formArrayName", "name"] }, providers: [formArrayNameProvider], usesInheritance: true, ngImport: i0 });
|
|
5569
|
-
}
|
|
5570
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormArrayName, decorators: [{
|
|
5571
|
-
type: Directive,
|
|
5572
|
-
args: [{
|
|
5573
|
-
selector: '[formArrayName]',
|
|
5574
|
-
providers: [formArrayNameProvider],
|
|
5575
|
-
standalone: false,
|
|
5576
|
-
}]
|
|
5577
|
-
}], ctorParameters: () => [{ type: ControlContainer, decorators: [{
|
|
5578
|
-
type: Optional
|
|
5579
|
-
}, {
|
|
5580
|
-
type: Host
|
|
5581
|
-
}, {
|
|
5582
|
-
type: SkipSelf
|
|
5583
|
-
}] }, { type: undefined, decorators: [{
|
|
5584
|
-
type: Optional
|
|
5585
|
-
}, {
|
|
5586
|
-
type: Self
|
|
5587
|
-
}, {
|
|
5588
|
-
type: Inject,
|
|
5589
|
-
args: [NG_VALIDATORS]
|
|
5590
|
-
}] }, { type: undefined, decorators: [{
|
|
5591
|
-
type: Optional
|
|
5592
|
-
}, {
|
|
5593
|
-
type: Self
|
|
5594
|
-
}, {
|
|
5595
|
-
type: Inject,
|
|
5596
|
-
args: [NG_ASYNC_VALIDATORS]
|
|
5597
|
-
}] }], propDecorators: { name: [{
|
|
5598
|
-
type: Input,
|
|
5599
|
-
args: ['formArrayName']
|
|
5600
|
-
}] } });
|
|
5601
|
-
function hasInvalidParent(parent) {
|
|
5602
|
-
return (!(parent instanceof FormGroupName) &&
|
|
5603
|
-
!(parent instanceof FormGroupDirective) &&
|
|
5604
|
-
!(parent instanceof FormArrayName));
|
|
5605
|
-
}
|
|
5606
|
-
|
|
5607
|
-
const controlNameBinding = {
|
|
5608
|
-
provide: NgControl,
|
|
5609
|
-
useExisting: forwardRef(() => FormControlName),
|
|
5610
|
-
};
|
|
5611
|
-
/**
|
|
5612
|
-
* @description
|
|
5613
|
-
* Syncs a `FormControl` in an existing `FormGroup` to a form control
|
|
5614
|
-
* element by name.
|
|
5615
|
-
*
|
|
5616
|
-
* @see [Reactive Forms Guide](guide/forms/reactive-forms)
|
|
5617
|
-
* @see {@link FormControl}
|
|
5618
|
-
* @see {@link AbstractControl}
|
|
5619
|
-
*
|
|
5620
|
-
* @usageNotes
|
|
5621
|
-
*
|
|
5622
|
-
* ### Register `FormControl` within a group
|
|
5623
|
-
*
|
|
5624
|
-
* The following example shows how to register multiple form controls within a form group
|
|
5625
|
-
* and set their value.
|
|
5626
|
-
*
|
|
5627
|
-
* {@example forms/ts/simpleFormGroup/simple_form_group_example.ts region='Component'}
|
|
5628
|
-
*
|
|
5629
|
-
* To see `formControlName` examples with different form control types, see:
|
|
5630
|
-
*
|
|
5631
|
-
* * Radio buttons: `RadioControlValueAccessor`
|
|
5632
|
-
* * Selects: `SelectControlValueAccessor`
|
|
5633
|
-
*
|
|
5634
|
-
* ### Use with ngModel is deprecated
|
|
5635
|
-
*
|
|
5636
|
-
* Support for using the `ngModel` input property and `ngModelChange` event with reactive
|
|
5637
|
-
* form directives has been deprecated in Angular v6 and is scheduled for removal in
|
|
5638
|
-
* a future version of Angular.
|
|
5639
|
-
*
|
|
5640
|
-
* @ngModule ReactiveFormsModule
|
|
5641
|
-
* @publicApi
|
|
5642
|
-
*/
|
|
5643
|
-
class FormControlName extends NgControl {
|
|
5644
|
-
_ngModelWarningConfig;
|
|
5645
|
-
_added = false;
|
|
5646
5382
|
/**
|
|
5647
|
-
*
|
|
5648
|
-
*
|
|
5383
|
+
* @description
|
|
5384
|
+
* Returns an array representing the path to this group. Because this directive
|
|
5385
|
+
* always lives at the top level of a form, it always an empty array.
|
|
5649
5386
|
*/
|
|
5650
|
-
|
|
5387
|
+
get path() {
|
|
5388
|
+
return [];
|
|
5389
|
+
}
|
|
5651
5390
|
/**
|
|
5652
5391
|
* @description
|
|
5653
|
-
*
|
|
5392
|
+
* Method that sets up the control directive in this group, re-calculates its value
|
|
5393
|
+
* and validity, and adds the instance to the internal list of directives.
|
|
5394
|
+
*
|
|
5395
|
+
* @param dir The `FormControlName` directive instance.
|
|
5654
5396
|
*/
|
|
5655
|
-
|
|
5397
|
+
addControl(dir) {
|
|
5398
|
+
const ctrl = this.form.get(dir.path);
|
|
5399
|
+
setUpControl(ctrl, dir, this.callSetDisabledState);
|
|
5400
|
+
ctrl.updateValueAndValidity({ emitEvent: false });
|
|
5401
|
+
this.directives.push(dir);
|
|
5402
|
+
return ctrl;
|
|
5403
|
+
}
|
|
5656
5404
|
/**
|
|
5657
5405
|
* @description
|
|
5658
|
-
*
|
|
5659
|
-
*
|
|
5660
|
-
*
|
|
5661
|
-
* The name in the form of a string is useful for individual forms,
|
|
5662
|
-
* while the numerical form allows for form controls to be bound
|
|
5663
|
-
* to indices when iterating over controls in a `FormArray`.
|
|
5406
|
+
* Retrieves the `FormControl` instance from the provided `FormControlName` directive
|
|
5407
|
+
*
|
|
5408
|
+
* @param dir The `FormControlName` directive instance.
|
|
5664
5409
|
*/
|
|
5665
|
-
|
|
5410
|
+
getControl(dir) {
|
|
5411
|
+
return this.form.get(dir.path);
|
|
5412
|
+
}
|
|
5666
5413
|
/**
|
|
5667
5414
|
* @description
|
|
5668
|
-
*
|
|
5415
|
+
* Removes the `FormControlName` instance from the internal list of directives
|
|
5416
|
+
*
|
|
5417
|
+
* @param dir The `FormControlName` directive instance.
|
|
5669
5418
|
*/
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5419
|
+
removeControl(dir) {
|
|
5420
|
+
cleanUpControl(dir.control || null, dir, /* validateControlPresenceOnChange */ false);
|
|
5421
|
+
removeListItem$1(this.directives, dir);
|
|
5422
|
+
}
|
|
5423
|
+
/**
|
|
5424
|
+
* Adds a new `FormGroupName` directive instance to the form.
|
|
5425
|
+
*
|
|
5426
|
+
* @param dir The `FormGroupName` directive instance.
|
|
5427
|
+
*/
|
|
5428
|
+
addFormGroup(dir) {
|
|
5429
|
+
this._setUpFormContainer(dir);
|
|
5430
|
+
}
|
|
5431
|
+
/**
|
|
5432
|
+
* Performs the necessary cleanup when a `FormGroupName` directive instance is removed from the
|
|
5433
|
+
* view.
|
|
5434
|
+
*
|
|
5435
|
+
* @param dir The `FormGroupName` directive instance.
|
|
5436
|
+
*/
|
|
5437
|
+
removeFormGroup(dir) {
|
|
5438
|
+
this._cleanUpFormContainer(dir);
|
|
5674
5439
|
}
|
|
5675
|
-
// TODO(kara): remove next 4 properties once deprecation period is over
|
|
5676
|
-
/** @deprecated as of v6 */
|
|
5677
|
-
model;
|
|
5678
|
-
/** @deprecated as of v6 */
|
|
5679
|
-
update = new EventEmitter();
|
|
5680
5440
|
/**
|
|
5681
5441
|
* @description
|
|
5682
|
-
*
|
|
5683
|
-
* all instances of FormControlName. Used to support warning config of "once".
|
|
5442
|
+
* Retrieves the `FormGroup` for a provided `FormGroupName` directive instance
|
|
5684
5443
|
*
|
|
5685
|
-
* @
|
|
5444
|
+
* @param dir The `FormGroupName` directive instance.
|
|
5686
5445
|
*/
|
|
5687
|
-
|
|
5446
|
+
getFormGroup(dir) {
|
|
5447
|
+
return this.form.get(dir.path);
|
|
5448
|
+
}
|
|
5688
5449
|
/**
|
|
5689
5450
|
* @description
|
|
5690
|
-
*
|
|
5691
|
-
* particular FormControlName instance. Used to support warning config of "always".
|
|
5451
|
+
* Retrieves the `FormArray` for a provided `FormArrayName` directive instance.
|
|
5692
5452
|
*
|
|
5693
|
-
* @
|
|
5453
|
+
* @param dir The `FormArrayName` directive instance.
|
|
5694
5454
|
*/
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
super();
|
|
5698
|
-
this._ngModelWarningConfig = _ngModelWarningConfig;
|
|
5699
|
-
this._parent = parent;
|
|
5700
|
-
this._setValidators(validators);
|
|
5701
|
-
this._setAsyncValidators(asyncValidators);
|
|
5702
|
-
this.valueAccessor = selectValueAccessor(this, valueAccessors);
|
|
5455
|
+
getFormArray(dir) {
|
|
5456
|
+
return this.form.get(dir.path);
|
|
5703
5457
|
}
|
|
5704
|
-
/**
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
}
|
|
5712
|
-
this.viewModel = this.model;
|
|
5713
|
-
this.formDirective.updateModel(this, this.model);
|
|
5714
|
-
}
|
|
5458
|
+
/**
|
|
5459
|
+
* Performs the necessary setup when a `FormArrayName` directive instance is added to the view.
|
|
5460
|
+
*
|
|
5461
|
+
* @param dir The `FormArrayName` directive instance.
|
|
5462
|
+
*/
|
|
5463
|
+
addFormArray(dir) {
|
|
5464
|
+
this._setUpFormContainer(dir);
|
|
5715
5465
|
}
|
|
5716
|
-
/**
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5466
|
+
/**
|
|
5467
|
+
* Performs the necessary cleanup when a `FormArrayName` directive instance is removed from the
|
|
5468
|
+
* view.
|
|
5469
|
+
*
|
|
5470
|
+
* @param dir The `FormArrayName` directive instance.
|
|
5471
|
+
*/
|
|
5472
|
+
removeFormArray(dir) {
|
|
5473
|
+
this._cleanUpFormContainer(dir);
|
|
5721
5474
|
}
|
|
5722
5475
|
/**
|
|
5723
|
-
*
|
|
5724
|
-
* Sets the new value for the view model and emits an `ngModelChange` event.
|
|
5476
|
+
* Sets the new value for the provided `FormControlName` directive.
|
|
5725
5477
|
*
|
|
5726
|
-
* @param
|
|
5478
|
+
* @param dir The `FormControlName` directive instance.
|
|
5479
|
+
* @param value The new value for the directive's control.
|
|
5727
5480
|
*/
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5481
|
+
updateModel(dir, value) {
|
|
5482
|
+
const ctrl = this.form.get(dir.path);
|
|
5483
|
+
ctrl.setValue(value);
|
|
5731
5484
|
}
|
|
5732
5485
|
/**
|
|
5733
5486
|
* @description
|
|
5734
|
-
*
|
|
5735
|
-
* Each index is the string name of the control on that level.
|
|
5487
|
+
* Method called when the "reset" event is triggered on the form.
|
|
5736
5488
|
*/
|
|
5737
|
-
|
|
5738
|
-
|
|
5489
|
+
onReset() {
|
|
5490
|
+
this.resetForm();
|
|
5739
5491
|
}
|
|
5740
5492
|
/**
|
|
5741
5493
|
* @description
|
|
5742
|
-
*
|
|
5494
|
+
* Resets the form to an initial value and resets its submitted status.
|
|
5495
|
+
*
|
|
5496
|
+
* @param value The new value for the form.
|
|
5743
5497
|
*/
|
|
5744
|
-
|
|
5745
|
-
|
|
5498
|
+
resetForm(value = undefined, options = {}) {
|
|
5499
|
+
this.form.reset(value, options);
|
|
5500
|
+
this._submittedReactive.set(false);
|
|
5501
|
+
if (options?.emitEvent !== false) {
|
|
5502
|
+
this.form._events.next(new FormResetEvent(this.form));
|
|
5503
|
+
}
|
|
5746
5504
|
}
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5505
|
+
/**
|
|
5506
|
+
* @description
|
|
5507
|
+
* Method called with the "submit" event is triggered on the form.
|
|
5508
|
+
* Triggers the `ngSubmit` emitter to emit the "submit" event as its payload.
|
|
5509
|
+
*
|
|
5510
|
+
* @param $event The "submit" event object
|
|
5511
|
+
*/
|
|
5512
|
+
onSubmit($event) {
|
|
5513
|
+
this.submitted = true;
|
|
5514
|
+
syncPendingControls(this.form, this.directives);
|
|
5515
|
+
this.ngSubmit.emit($event);
|
|
5516
|
+
this.form._events.next(new FormSubmittedEvent(this.control));
|
|
5517
|
+
// Forms with `method="dialog"` have some special behavior that won't reload the page and that
|
|
5518
|
+
// shouldn't be prevented. Note that we need to null check the `event` and the `target`, because
|
|
5519
|
+
// some internal apps call this method directly with the wrong arguments.
|
|
5520
|
+
return $event?.target?.method === 'dialog';
|
|
5521
|
+
}
|
|
5522
|
+
/** @internal */
|
|
5523
|
+
_updateDomValue() {
|
|
5524
|
+
this.directives.forEach((dir) => {
|
|
5525
|
+
const oldCtrl = dir.control;
|
|
5526
|
+
const newCtrl = this.form.get(dir.path);
|
|
5527
|
+
if (oldCtrl !== newCtrl) {
|
|
5528
|
+
// Note: the value of the `dir.control` may not be defined, for example when it's a first
|
|
5529
|
+
// `FormControl` that is added to a `FormGroup`/`FormArray` instance (via `addControl` call).
|
|
5530
|
+
cleanUpControl(oldCtrl || null, dir);
|
|
5531
|
+
// Check whether new control at the same location inside the corresponding `FormGroup`/`FormArray` is an
|
|
5532
|
+
// instance of `FormControl` and perform control setup only if that's the case.
|
|
5533
|
+
// Note: we don't need to clear the list of directives (`this.directives`) here, it would be
|
|
5534
|
+
// taken care of in the `removeControl` method invoked when corresponding `formControlName`
|
|
5535
|
+
// directive instance is being removed (invoked from `FormControlName.ngOnDestroy`).
|
|
5536
|
+
if (isFormControl(newCtrl)) {
|
|
5537
|
+
setUpControl(newCtrl, dir, this.callSetDisabledState);
|
|
5538
|
+
dir.control = newCtrl;
|
|
5539
|
+
}
|
|
5540
|
+
}
|
|
5541
|
+
});
|
|
5542
|
+
this.form._updateTreeValidity({ emitEvent: false });
|
|
5543
|
+
}
|
|
5544
|
+
_setUpFormContainer(dir) {
|
|
5545
|
+
const ctrl = this.form.get(dir.path);
|
|
5546
|
+
setUpFormContainer(ctrl, dir);
|
|
5547
|
+
// NOTE: this operation looks unnecessary in case no new validators were added in
|
|
5548
|
+
// `setUpFormContainer` call. Consider updating this code to match the logic in
|
|
5549
|
+
// `_cleanUpFormContainer` function.
|
|
5550
|
+
ctrl.updateValueAndValidity({ emitEvent: false });
|
|
5551
|
+
}
|
|
5552
|
+
_cleanUpFormContainer(dir) {
|
|
5553
|
+
if (this.form) {
|
|
5554
|
+
const ctrl = this.form.get(dir.path);
|
|
5555
|
+
if (ctrl) {
|
|
5556
|
+
const isControlUpdated = cleanUpFormContainer(ctrl, dir);
|
|
5557
|
+
if (isControlUpdated) {
|
|
5558
|
+
// Run validity check only in case a control was updated (i.e. view validators were
|
|
5559
|
+
// removed) as removing view validators might cause validity to change.
|
|
5560
|
+
ctrl.updateValueAndValidity({ emitEvent: false });
|
|
5561
|
+
}
|
|
5562
|
+
}
|
|
5750
5563
|
}
|
|
5751
|
-
this.control = this.formDirective.addControl(this);
|
|
5752
|
-
this._added = true;
|
|
5753
5564
|
}
|
|
5754
|
-
|
|
5755
|
-
|
|
5565
|
+
_updateRegistrations() {
|
|
5566
|
+
this.form._registerOnCollectionChange(this._onCollectionChange);
|
|
5567
|
+
if (this._oldForm) {
|
|
5568
|
+
this._oldForm._registerOnCollectionChange(() => { });
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5571
|
+
_updateValidators() {
|
|
5572
|
+
setUpValidators(this.form, this);
|
|
5573
|
+
if (this._oldForm) {
|
|
5574
|
+
cleanUpValidators(this._oldForm, this);
|
|
5575
|
+
}
|
|
5576
|
+
}
|
|
5577
|
+
_checkFormPresent() {
|
|
5578
|
+
if (!this.form && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
5579
|
+
throw missingFormException();
|
|
5580
|
+
}
|
|
5581
|
+
}
|
|
5582
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: AbstractFormDirective, deps: [{ token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: CALL_SET_DISABLED_STATE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
5583
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: AbstractFormDirective, isStandalone: true, usesInheritance: true, usesOnChanges: true, ngImport: i0 });
|
|
5756
5584
|
}
|
|
5757
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
5758
|
-
type: Directive
|
|
5759
|
-
|
|
5760
|
-
selector: '[formControlName]',
|
|
5761
|
-
providers: [controlNameBinding],
|
|
5762
|
-
standalone: false,
|
|
5763
|
-
}]
|
|
5764
|
-
}], ctorParameters: () => [{ type: ControlContainer, decorators: [{
|
|
5765
|
-
type: Optional
|
|
5766
|
-
}, {
|
|
5767
|
-
type: Host
|
|
5768
|
-
}, {
|
|
5769
|
-
type: SkipSelf
|
|
5770
|
-
}] }, { type: undefined, decorators: [{
|
|
5585
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: AbstractFormDirective, decorators: [{
|
|
5586
|
+
type: Directive
|
|
5587
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
5771
5588
|
type: Optional
|
|
5772
5589
|
}, {
|
|
5773
5590
|
type: Self
|
|
@@ -5783,1623 +5600,1897 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2",
|
|
|
5783
5600
|
args: [NG_ASYNC_VALIDATORS]
|
|
5784
5601
|
}] }, { type: undefined, decorators: [{
|
|
5785
5602
|
type: Optional
|
|
5786
|
-
}, {
|
|
5787
|
-
type: Self
|
|
5788
|
-
}, {
|
|
5789
|
-
type: Inject,
|
|
5790
|
-
args: [NG_VALUE_ACCESSOR]
|
|
5791
|
-
}] }, { type: undefined, decorators: [{
|
|
5792
|
-
type: Optional
|
|
5793
5603
|
}, {
|
|
5794
5604
|
type: Inject,
|
|
5795
|
-
args: [
|
|
5796
|
-
}] }]
|
|
5797
|
-
type: Input,
|
|
5798
|
-
args: ['formControlName']
|
|
5799
|
-
}], isDisabled: [{
|
|
5800
|
-
type: Input,
|
|
5801
|
-
args: ['disabled']
|
|
5802
|
-
}], model: [{
|
|
5803
|
-
type: Input,
|
|
5804
|
-
args: ['ngModel']
|
|
5805
|
-
}], update: [{
|
|
5806
|
-
type: Output,
|
|
5807
|
-
args: ['ngModelChange']
|
|
5808
|
-
}] } });
|
|
5809
|
-
function checkParentType(parent, name) {
|
|
5810
|
-
if (!(parent instanceof FormGroupName) && parent instanceof AbstractFormGroupDirective) {
|
|
5811
|
-
throw ngModelGroupException();
|
|
5812
|
-
}
|
|
5813
|
-
else if (!(parent instanceof FormGroupName) &&
|
|
5814
|
-
!(parent instanceof FormGroupDirective) &&
|
|
5815
|
-
!(parent instanceof FormArrayName)) {
|
|
5816
|
-
throw controlParentException(name);
|
|
5817
|
-
}
|
|
5818
|
-
}
|
|
5605
|
+
args: [CALL_SET_DISABLED_STATE]
|
|
5606
|
+
}] }] });
|
|
5819
5607
|
|
|
5820
|
-
const
|
|
5821
|
-
provide:
|
|
5822
|
-
useExisting: forwardRef(() =>
|
|
5823
|
-
multi: true,
|
|
5608
|
+
const formDirectiveProvider$1 = {
|
|
5609
|
+
provide: ControlContainer,
|
|
5610
|
+
useExisting: forwardRef(() => FormArrayDirective),
|
|
5824
5611
|
};
|
|
5825
|
-
function _buildValueString$1(id, value) {
|
|
5826
|
-
if (id == null)
|
|
5827
|
-
return `${value}`;
|
|
5828
|
-
if (value && typeof value === 'object')
|
|
5829
|
-
value = 'Object';
|
|
5830
|
-
return `${id}: ${value}`.slice(0, 50);
|
|
5831
|
-
}
|
|
5832
|
-
function _extractId$1(valueString) {
|
|
5833
|
-
return valueString.split(':')[0];
|
|
5834
|
-
}
|
|
5835
5612
|
/**
|
|
5836
5613
|
* @description
|
|
5837
|
-
* The `ControlValueAccessor` for writing select control values and listening to select control
|
|
5838
|
-
* changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
|
|
5839
|
-
* `NgModel` directives.
|
|
5840
5614
|
*
|
|
5841
|
-
*
|
|
5842
|
-
*
|
|
5843
|
-
* ### Using select controls in a reactive form
|
|
5844
|
-
*
|
|
5845
|
-
* The following examples show how to use a select control in a reactive form.
|
|
5846
|
-
*
|
|
5847
|
-
* {@example forms/ts/reactiveSelectControl/reactive_select_control_example.ts region='Component'}
|
|
5615
|
+
* Binds an existing `FormArray` to a DOM element.
|
|
5848
5616
|
*
|
|
5849
|
-
*
|
|
5617
|
+
* This directive accepts an existing `FormArray` instance. It will then use this
|
|
5618
|
+
* `FormArray` instance to match any child `FormControl`, `FormGroup`/`FormRecord`,
|
|
5619
|
+
* and `FormArray` instances to child `FormControlName`, `FormGroupName`,
|
|
5620
|
+
* and `FormArrayName` directives.
|
|
5850
5621
|
*
|
|
5851
|
-
*
|
|
5852
|
-
*
|
|
5622
|
+
* @see [Reactive Forms Guide](guide/reactive-forms)
|
|
5623
|
+
* @see {@link AbstractControl}
|
|
5853
5624
|
*
|
|
5854
|
-
*
|
|
5625
|
+
* @usageNotes
|
|
5626
|
+
* ### Register Form Array
|
|
5855
5627
|
*
|
|
5856
|
-
*
|
|
5628
|
+
* The following example registers a `FormArray` with first name and last name controls,
|
|
5629
|
+
* and listens for the *ngSubmit* event when the button is clicked.
|
|
5857
5630
|
*
|
|
5858
|
-
*
|
|
5859
|
-
*
|
|
5860
|
-
|
|
5861
|
-
|
|
5631
|
+
* @ngModule ReactiveFormsModule
|
|
5632
|
+
* @publicApi
|
|
5633
|
+
*/
|
|
5634
|
+
class FormArrayDirective extends AbstractFormDirective {
|
|
5635
|
+
/**
|
|
5636
|
+
* @description
|
|
5637
|
+
* Tracks the `FormArray` bound to this directive.
|
|
5638
|
+
*/
|
|
5639
|
+
form = null;
|
|
5640
|
+
/**
|
|
5641
|
+
* @description
|
|
5642
|
+
* Emits an event when the form submission has been triggered.
|
|
5643
|
+
*/
|
|
5644
|
+
ngSubmit = new EventEmitter();
|
|
5645
|
+
/**
|
|
5646
|
+
* @description
|
|
5647
|
+
* Returns the `FormArray` bound to this directive.
|
|
5648
|
+
*/
|
|
5649
|
+
get control() {
|
|
5650
|
+
return this.form;
|
|
5651
|
+
}
|
|
5652
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormArrayDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
5653
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: FormArrayDirective, isStandalone: false, selector: "[formArray]", inputs: { form: ["formArray", "form"] }, outputs: { ngSubmit: "ngSubmit" }, host: { listeners: { "submit": "onSubmit($event)", "reset": "onReset()" } }, providers: [formDirectiveProvider$1], exportAs: ["ngForm"], usesInheritance: true, ngImport: i0 });
|
|
5654
|
+
}
|
|
5655
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormArrayDirective, decorators: [{
|
|
5656
|
+
type: Directive,
|
|
5657
|
+
args: [{
|
|
5658
|
+
selector: '[formArray]',
|
|
5659
|
+
providers: [formDirectiveProvider$1],
|
|
5660
|
+
host: { '(submit)': 'onSubmit($event)', '(reset)': 'onReset()' },
|
|
5661
|
+
exportAs: 'ngForm',
|
|
5662
|
+
standalone: false,
|
|
5663
|
+
}]
|
|
5664
|
+
}], propDecorators: { form: [{
|
|
5665
|
+
type: Input,
|
|
5666
|
+
args: ['formArray']
|
|
5667
|
+
}], ngSubmit: [{
|
|
5668
|
+
type: Output
|
|
5669
|
+
}] } });
|
|
5670
|
+
|
|
5671
|
+
/**
|
|
5672
|
+
* Token to provide to turn off the ngModel warning on formControl and formControlName.
|
|
5673
|
+
*/
|
|
5674
|
+
const NG_MODEL_WITH_FORM_CONTROL_WARNING = new InjectionToken(ngDevMode ? 'NgModelWithFormControlWarning' : '');
|
|
5675
|
+
const formControlBinding = {
|
|
5676
|
+
provide: NgControl,
|
|
5677
|
+
useExisting: forwardRef(() => FormControlDirective),
|
|
5678
|
+
};
|
|
5679
|
+
/**
|
|
5680
|
+
* @description
|
|
5681
|
+
* Synchronizes a standalone `FormControl` instance to a form control element.
|
|
5862
5682
|
*
|
|
5863
|
-
*
|
|
5864
|
-
*
|
|
5865
|
-
*
|
|
5683
|
+
* Note that support for using the `ngModel` input property and `ngModelChange` event with reactive
|
|
5684
|
+
* form directives was deprecated in Angular v6 and is scheduled for removal in
|
|
5685
|
+
* a future version of Angular.
|
|
5866
5686
|
*
|
|
5867
|
-
*
|
|
5868
|
-
*
|
|
5869
|
-
*
|
|
5687
|
+
* @see [Reactive Forms Guide](guide/forms/reactive-forms)
|
|
5688
|
+
* @see {@link FormControl}
|
|
5689
|
+
* @see {@link AbstractControl}
|
|
5870
5690
|
*
|
|
5871
|
-
*
|
|
5872
|
-
* <select [compareWith]="compareFn" [formControl]="selectedCountriesControl">
|
|
5873
|
-
* @for(country of countries; track $index) {
|
|
5874
|
-
* <option[ngValue]="country">{{country.name}}</option>
|
|
5875
|
-
* }
|
|
5876
|
-
* </select>
|
|
5691
|
+
* @usageNotes
|
|
5877
5692
|
*
|
|
5878
|
-
*
|
|
5879
|
-
* return c1 && c2 ? c1.id === c2.id : c1 === c2;
|
|
5880
|
-
* }
|
|
5881
|
-
* ```
|
|
5693
|
+
* The following example shows how to register a standalone control and set its value.
|
|
5882
5694
|
*
|
|
5883
|
-
*
|
|
5884
|
-
* for selects in IE, see:
|
|
5885
|
-
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event#browser_compatibility
|
|
5695
|
+
* {@example forms/ts/simpleFormControl/simple_form_control_example.ts region='Component'}
|
|
5886
5696
|
*
|
|
5887
5697
|
* @ngModule ReactiveFormsModule
|
|
5888
|
-
* @ngModule FormsModule
|
|
5889
5698
|
* @publicApi
|
|
5890
5699
|
*/
|
|
5891
|
-
class
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
/** @internal */
|
|
5895
|
-
_optionMap = new Map();
|
|
5896
|
-
/** @internal */
|
|
5897
|
-
_idCounter = 0;
|
|
5700
|
+
class FormControlDirective extends NgControl {
|
|
5701
|
+
_ngModelWarningConfig;
|
|
5702
|
+
callSetDisabledState;
|
|
5898
5703
|
/**
|
|
5899
|
-
*
|
|
5900
|
-
*
|
|
5901
|
-
* checking for changes.
|
|
5704
|
+
* Internal reference to the view model value.
|
|
5705
|
+
* @docs-private
|
|
5902
5706
|
*/
|
|
5903
|
-
|
|
5904
|
-
if (typeof fn !== 'function' && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
5905
|
-
throw new _RuntimeError(1201 /* RuntimeErrorCode.COMPAREWITH_NOT_A_FN */, `compareWith must be a function, but received ${JSON.stringify(fn)}`);
|
|
5906
|
-
}
|
|
5907
|
-
this._compareWith = fn;
|
|
5908
|
-
}
|
|
5909
|
-
_compareWith = Object.is;
|
|
5910
|
-
// We need this because we might be in the process of destroying the root
|
|
5911
|
-
// injector, which is marked as destroyed before running destroy hooks.
|
|
5912
|
-
// Attempting to use afterNextRender with the node injector would evntually
|
|
5913
|
-
// run into that already destroyed injector.
|
|
5914
|
-
appRefInjector = inject(ApplicationRef).injector;
|
|
5915
|
-
destroyRef = inject(DestroyRef);
|
|
5916
|
-
cdr = inject(ChangeDetectorRef);
|
|
5917
|
-
_queuedWrite = false;
|
|
5707
|
+
viewModel;
|
|
5918
5708
|
/**
|
|
5919
|
-
*
|
|
5920
|
-
*
|
|
5921
|
-
* more _compareValue calls than the number of option elements (issue #41330).
|
|
5922
|
-
*
|
|
5923
|
-
* Secondly, calling writeValue when rendering individual option elements instead of after they
|
|
5924
|
-
* are all rendered caused an issue in Safari and IE 11 where the first option element failed
|
|
5925
|
-
* to be deselected when no option matched the select ngModel. This was because Angular would
|
|
5926
|
-
* set the select element's value property before appending the option's child text node to the
|
|
5927
|
-
* DOM (issue #14505).
|
|
5928
|
-
*
|
|
5929
|
-
* Finally, this approach is necessary to avoid an issue with delayed element removal when
|
|
5930
|
-
* using the animations module (in all browsers). Otherwise when a selected option is removed
|
|
5931
|
-
* (so no option matches the ngModel anymore), Angular would change the select element value
|
|
5932
|
-
* before actually removing the option from the DOM. Then when the option is finally removed
|
|
5933
|
-
* from the DOM, the browser would change the select value to that of the first option, even
|
|
5934
|
-
* though it doesn't match the ngModel (issue #18430).
|
|
5935
|
-
*
|
|
5936
|
-
* @internal
|
|
5709
|
+
* @description
|
|
5710
|
+
* Tracks the `FormControl` instance bound to the directive.
|
|
5937
5711
|
*/
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5712
|
+
form;
|
|
5713
|
+
/**
|
|
5714
|
+
* @description
|
|
5715
|
+
* Triggers a warning in dev mode that this input should not be used with reactive forms.
|
|
5716
|
+
*/
|
|
5717
|
+
set isDisabled(isDisabled) {
|
|
5718
|
+
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
5719
|
+
console.warn(disabledAttrWarning);
|
|
5941
5720
|
}
|
|
5942
|
-
this._queuedWrite = true;
|
|
5943
|
-
afterNextRender({
|
|
5944
|
-
write: () => {
|
|
5945
|
-
if (this.destroyRef.destroyed) {
|
|
5946
|
-
return;
|
|
5947
|
-
}
|
|
5948
|
-
this._queuedWrite = false;
|
|
5949
|
-
this.writeValue(this.value);
|
|
5950
|
-
},
|
|
5951
|
-
}, { injector: this.appRefInjector });
|
|
5952
5721
|
}
|
|
5722
|
+
// TODO(kara): remove next 4 properties once deprecation period is over
|
|
5723
|
+
/** @deprecated as of v6 */
|
|
5724
|
+
model;
|
|
5725
|
+
/** @deprecated as of v6 */
|
|
5726
|
+
update = new EventEmitter();
|
|
5953
5727
|
/**
|
|
5954
|
-
*
|
|
5955
|
-
*
|
|
5728
|
+
* @description
|
|
5729
|
+
* Static property used to track whether any ngModel warnings have been sent across
|
|
5730
|
+
* all instances of FormControlDirective. Used to support warning config of "once".
|
|
5731
|
+
*
|
|
5732
|
+
* @internal
|
|
5956
5733
|
*/
|
|
5957
|
-
|
|
5958
|
-
// TODO(atscott): This could likely be optimized more by only marking for check if the value is changed
|
|
5959
|
-
// note that this needs to include both the internal value and the value in the DOM.
|
|
5960
|
-
this.cdr.markForCheck();
|
|
5961
|
-
this.value = value;
|
|
5962
|
-
const id = this._getOptionId(value);
|
|
5963
|
-
const valueString = _buildValueString$1(id, value);
|
|
5964
|
-
this.setProperty('value', valueString);
|
|
5965
|
-
}
|
|
5734
|
+
static _ngModelWarningSentOnce = false;
|
|
5966
5735
|
/**
|
|
5967
|
-
*
|
|
5968
|
-
*
|
|
5736
|
+
* @description
|
|
5737
|
+
* Instance property used to track whether an ngModel warning has been sent out for this
|
|
5738
|
+
* particular `FormControlDirective` instance. Used to support warning config of "always".
|
|
5739
|
+
*
|
|
5740
|
+
* @internal
|
|
5969
5741
|
*/
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
return (this._idCounter++).toString();
|
|
5742
|
+
_ngModelWarningSent = false;
|
|
5743
|
+
constructor(validators, asyncValidators, valueAccessors, _ngModelWarningConfig, callSetDisabledState) {
|
|
5744
|
+
super();
|
|
5745
|
+
this._ngModelWarningConfig = _ngModelWarningConfig;
|
|
5746
|
+
this.callSetDisabledState = callSetDisabledState;
|
|
5747
|
+
this._setValidators(validators);
|
|
5748
|
+
this._setAsyncValidators(asyncValidators);
|
|
5749
|
+
this.valueAccessor = selectValueAccessor(this, valueAccessors);
|
|
5979
5750
|
}
|
|
5980
|
-
/** @
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5751
|
+
/** @docs-private */
|
|
5752
|
+
ngOnChanges(changes) {
|
|
5753
|
+
if (this._isControlChanged(changes)) {
|
|
5754
|
+
const previousForm = changes['form'].previousValue;
|
|
5755
|
+
if (previousForm) {
|
|
5756
|
+
cleanUpControl(previousForm, this, /* validateControlPresenceOnChange */ false);
|
|
5757
|
+
}
|
|
5758
|
+
setUpControl(this.form, this, this.callSetDisabledState);
|
|
5759
|
+
this.form.updateValueAndValidity({ emitEvent: false });
|
|
5760
|
+
}
|
|
5761
|
+
if (isPropertyUpdated(changes, this.viewModel)) {
|
|
5762
|
+
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
5763
|
+
_ngModelWarning('formControl', FormControlDirective, this, this._ngModelWarningConfig);
|
|
5764
|
+
}
|
|
5765
|
+
this.form.setValue(this.model);
|
|
5766
|
+
this.viewModel = this.model;
|
|
5985
5767
|
}
|
|
5986
|
-
return null;
|
|
5987
5768
|
}
|
|
5988
|
-
/** @
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5769
|
+
/** @docs-private */
|
|
5770
|
+
ngOnDestroy() {
|
|
5771
|
+
if (this.form) {
|
|
5772
|
+
cleanUpControl(this.form, this, /* validateControlPresenceOnChange */ false);
|
|
5773
|
+
}
|
|
5992
5774
|
}
|
|
5993
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: SelectControlValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
5994
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: SelectControlValueAccessor, isStandalone: false, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: { compareWith: "compareWith" }, host: { listeners: { "change": "onChange($any($event.target).value)", "blur": "onTouched()" } }, providers: [SELECT_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 });
|
|
5995
|
-
}
|
|
5996
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: SelectControlValueAccessor, decorators: [{
|
|
5997
|
-
type: Directive,
|
|
5998
|
-
args: [{
|
|
5999
|
-
selector: 'select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]',
|
|
6000
|
-
host: { '(change)': 'onChange($any($event.target).value)', '(blur)': 'onTouched()' },
|
|
6001
|
-
providers: [SELECT_VALUE_ACCESSOR],
|
|
6002
|
-
standalone: false,
|
|
6003
|
-
}]
|
|
6004
|
-
}], propDecorators: { compareWith: [{
|
|
6005
|
-
type: Input
|
|
6006
|
-
}] } });
|
|
6007
|
-
/**
|
|
6008
|
-
* @description
|
|
6009
|
-
* Marks `<option>` as dynamic, so Angular can be notified when options change.
|
|
6010
|
-
*
|
|
6011
|
-
* @see {@link SelectControlValueAccessor}
|
|
6012
|
-
*
|
|
6013
|
-
* @ngModule ReactiveFormsModule
|
|
6014
|
-
* @ngModule FormsModule
|
|
6015
|
-
* @publicApi
|
|
6016
|
-
*/
|
|
6017
|
-
class NgSelectOption {
|
|
6018
|
-
_element;
|
|
6019
|
-
_renderer;
|
|
6020
|
-
_select;
|
|
6021
5775
|
/**
|
|
6022
5776
|
* @description
|
|
6023
|
-
*
|
|
5777
|
+
* Returns an array that represents the path from the top-level form to this control.
|
|
5778
|
+
* Each index is the string name of the control on that level.
|
|
6024
5779
|
*/
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
this._element = _element;
|
|
6028
|
-
this._renderer = _renderer;
|
|
6029
|
-
this._select = _select;
|
|
6030
|
-
if (this._select)
|
|
6031
|
-
this.id = this._select._registerOption();
|
|
5780
|
+
get path() {
|
|
5781
|
+
return [];
|
|
6032
5782
|
}
|
|
6033
5783
|
/**
|
|
6034
5784
|
* @description
|
|
6035
|
-
*
|
|
6036
|
-
* ngValue supports binding to objects.
|
|
5785
|
+
* The `FormControl` bound to this directive.
|
|
6037
5786
|
*/
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
return;
|
|
6041
|
-
this._select._optionMap.set(this.id, value);
|
|
6042
|
-
this._setElementValue(_buildValueString$1(this.id, value));
|
|
6043
|
-
this._select._writeValueAfterRender();
|
|
5787
|
+
get control() {
|
|
5788
|
+
return this.form;
|
|
6044
5789
|
}
|
|
6045
5790
|
/**
|
|
6046
5791
|
* @description
|
|
6047
|
-
*
|
|
6048
|
-
*
|
|
5792
|
+
* Sets the new value for the view model and emits an `ngModelChange` event.
|
|
5793
|
+
*
|
|
5794
|
+
* @param newValue The new value for the view model.
|
|
6049
5795
|
*/
|
|
6050
|
-
|
|
6051
|
-
this.
|
|
6052
|
-
|
|
6053
|
-
this._select._writeValueAfterRender();
|
|
6054
|
-
}
|
|
6055
|
-
/** @internal */
|
|
6056
|
-
_setElementValue(value) {
|
|
6057
|
-
this._renderer.setProperty(this._element.nativeElement, 'value', value);
|
|
5796
|
+
viewToModelUpdate(newValue) {
|
|
5797
|
+
this.viewModel = newValue;
|
|
5798
|
+
this.update.emit(newValue);
|
|
6058
5799
|
}
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
if (this._select) {
|
|
6062
|
-
this._select._optionMap.delete(this.id);
|
|
6063
|
-
this._select._writeValueAfterRender();
|
|
6064
|
-
}
|
|
5800
|
+
_isControlChanged(changes) {
|
|
5801
|
+
return changes.hasOwnProperty('form');
|
|
6065
5802
|
}
|
|
6066
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
6067
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type:
|
|
5803
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormControlDirective, deps: [{ token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: NG_VALUE_ACCESSOR, optional: true, self: true }, { token: NG_MODEL_WITH_FORM_CONTROL_WARNING, optional: true }, { token: CALL_SET_DISABLED_STATE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
5804
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: FormControlDirective, isStandalone: false, selector: "[formControl]", inputs: { form: ["formControl", "form"], isDisabled: ["disabled", "isDisabled"], model: ["ngModel", "model"] }, outputs: { update: "ngModelChange" }, providers: [formControlBinding], exportAs: ["ngForm"], usesInheritance: true, usesOnChanges: true, ngImport: i0 });
|
|
6068
5805
|
}
|
|
6069
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
5806
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormControlDirective, decorators: [{
|
|
6070
5807
|
type: Directive,
|
|
6071
5808
|
args: [{
|
|
6072
|
-
selector: '
|
|
5809
|
+
selector: '[formControl]',
|
|
5810
|
+
providers: [formControlBinding],
|
|
5811
|
+
exportAs: 'ngForm',
|
|
6073
5812
|
standalone: false,
|
|
6074
5813
|
}]
|
|
6075
|
-
}], ctorParameters: () => [{ type:
|
|
5814
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
6076
5815
|
type: Optional
|
|
6077
5816
|
}, {
|
|
6078
|
-
type:
|
|
6079
|
-
}
|
|
5817
|
+
type: Self
|
|
5818
|
+
}, {
|
|
5819
|
+
type: Inject,
|
|
5820
|
+
args: [NG_VALIDATORS]
|
|
5821
|
+
}] }, { type: undefined, decorators: [{
|
|
5822
|
+
type: Optional
|
|
5823
|
+
}, {
|
|
5824
|
+
type: Self
|
|
5825
|
+
}, {
|
|
5826
|
+
type: Inject,
|
|
5827
|
+
args: [NG_ASYNC_VALIDATORS]
|
|
5828
|
+
}] }, { type: undefined, decorators: [{
|
|
5829
|
+
type: Optional
|
|
5830
|
+
}, {
|
|
5831
|
+
type: Self
|
|
5832
|
+
}, {
|
|
5833
|
+
type: Inject,
|
|
5834
|
+
args: [NG_VALUE_ACCESSOR]
|
|
5835
|
+
}] }, { type: undefined, decorators: [{
|
|
5836
|
+
type: Optional
|
|
5837
|
+
}, {
|
|
5838
|
+
type: Inject,
|
|
5839
|
+
args: [NG_MODEL_WITH_FORM_CONTROL_WARNING]
|
|
5840
|
+
}] }, { type: undefined, decorators: [{
|
|
5841
|
+
type: Optional
|
|
5842
|
+
}, {
|
|
5843
|
+
type: Inject,
|
|
5844
|
+
args: [CALL_SET_DISABLED_STATE]
|
|
5845
|
+
}] }], propDecorators: { form: [{
|
|
6080
5846
|
type: Input,
|
|
6081
|
-
args: ['
|
|
6082
|
-
}],
|
|
5847
|
+
args: ['formControl']
|
|
5848
|
+
}], isDisabled: [{
|
|
6083
5849
|
type: Input,
|
|
6084
|
-
args: ['
|
|
5850
|
+
args: ['disabled']
|
|
5851
|
+
}], model: [{
|
|
5852
|
+
type: Input,
|
|
5853
|
+
args: ['ngModel']
|
|
5854
|
+
}], update: [{
|
|
5855
|
+
type: Output,
|
|
5856
|
+
args: ['ngModelChange']
|
|
6085
5857
|
}] } });
|
|
6086
5858
|
|
|
6087
|
-
const
|
|
6088
|
-
provide:
|
|
6089
|
-
useExisting: forwardRef(() =>
|
|
6090
|
-
multi: true,
|
|
5859
|
+
const formGroupNameProvider = {
|
|
5860
|
+
provide: ControlContainer,
|
|
5861
|
+
useExisting: forwardRef(() => FormGroupName),
|
|
6091
5862
|
};
|
|
6092
|
-
function _buildValueString(id, value) {
|
|
6093
|
-
if (id == null)
|
|
6094
|
-
return `${value}`;
|
|
6095
|
-
if (typeof value === 'string')
|
|
6096
|
-
value = `'${value}'`;
|
|
6097
|
-
if (value && typeof value === 'object')
|
|
6098
|
-
value = 'Object';
|
|
6099
|
-
return `${id}: ${value}`.slice(0, 50);
|
|
6100
|
-
}
|
|
6101
|
-
function _extractId(valueString) {
|
|
6102
|
-
return valueString.split(':')[0];
|
|
6103
|
-
}
|
|
6104
5863
|
/**
|
|
6105
5864
|
* @description
|
|
6106
|
-
* The `ControlValueAccessor` for writing multi-select control values and listening to multi-select
|
|
6107
|
-
* control changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
|
|
6108
|
-
* `NgModel` directives.
|
|
6109
5865
|
*
|
|
6110
|
-
*
|
|
5866
|
+
* Syncs a nested `FormGroup` or `FormRecord` to a DOM element.
|
|
5867
|
+
*
|
|
5868
|
+
* This directive can only be used with a parent `FormGroupDirective`.
|
|
5869
|
+
*
|
|
5870
|
+
* It accepts the string name of the nested `FormGroup` or `FormRecord` to link, and
|
|
5871
|
+
* looks for a `FormGroup` or `FormRecord` registered with that name in the parent
|
|
5872
|
+
* `FormGroup` instance you passed into `FormGroupDirective`.
|
|
5873
|
+
*
|
|
5874
|
+
* Use nested form groups to validate a sub-group of a
|
|
5875
|
+
* form separately from the rest or to group the values of certain
|
|
5876
|
+
* controls into their own nested object.
|
|
5877
|
+
*
|
|
5878
|
+
* @see [Reactive Forms Guide](guide/forms/reactive-forms)
|
|
6111
5879
|
*
|
|
6112
5880
|
* @usageNotes
|
|
6113
5881
|
*
|
|
6114
|
-
* ###
|
|
5882
|
+
* ### Access the group by name
|
|
6115
5883
|
*
|
|
6116
|
-
* The
|
|
5884
|
+
* The following example uses the `AbstractControl.get` method to access the
|
|
5885
|
+
* associated `FormGroup`
|
|
6117
5886
|
*
|
|
6118
5887
|
* ```ts
|
|
6119
|
-
*
|
|
5888
|
+
* this.form.get('name');
|
|
6120
5889
|
* ```
|
|
6121
5890
|
*
|
|
6122
|
-
*
|
|
6123
|
-
*
|
|
6124
|
-
*
|
|
6125
|
-
*
|
|
6126
|
-
*
|
|
6127
|
-
*
|
|
5891
|
+
* ### Access individual controls in the group
|
|
5892
|
+
*
|
|
5893
|
+
* The following example uses the `AbstractControl.get` method to access
|
|
5894
|
+
* individual controls within the group using dot syntax.
|
|
5895
|
+
*
|
|
5896
|
+
* ```ts
|
|
5897
|
+
* this.form.get('name.first');
|
|
6128
5898
|
* ```
|
|
6129
5899
|
*
|
|
6130
|
-
* ###
|
|
5900
|
+
* ### Register a nested `FormGroup`.
|
|
6131
5901
|
*
|
|
6132
|
-
*
|
|
6133
|
-
*
|
|
5902
|
+
* The following example registers a nested *name* `FormGroup` within an existing `FormGroup`,
|
|
5903
|
+
* and provides methods to retrieve the nested `FormGroup` and individual controls.
|
|
5904
|
+
*
|
|
5905
|
+
* {@example forms/ts/nestedFormGroup/nested_form_group_example.ts region='Component'}
|
|
6134
5906
|
*
|
|
6135
5907
|
* @ngModule ReactiveFormsModule
|
|
6136
|
-
* @ngModule FormsModule
|
|
6137
5908
|
* @publicApi
|
|
6138
5909
|
*/
|
|
6139
|
-
class
|
|
6140
|
-
/**
|
|
6141
|
-
* The current value.
|
|
6142
|
-
* @docs-private
|
|
6143
|
-
*/
|
|
6144
|
-
value;
|
|
6145
|
-
/** @internal */
|
|
6146
|
-
_optionMap = new Map();
|
|
6147
|
-
/** @internal */
|
|
6148
|
-
_idCounter = 0;
|
|
5910
|
+
class FormGroupName extends AbstractFormGroupDirective {
|
|
6149
5911
|
/**
|
|
6150
5912
|
* @description
|
|
6151
|
-
* Tracks the
|
|
6152
|
-
*
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
}
|
|
6158
|
-
this._compareWith = fn;
|
|
6159
|
-
}
|
|
6160
|
-
_compareWith = Object.is;
|
|
6161
|
-
/**
|
|
6162
|
-
* Sets the "value" property on one or of more of the select's options.
|
|
6163
|
-
* @docs-private
|
|
6164
|
-
*/
|
|
6165
|
-
writeValue(value) {
|
|
6166
|
-
this.value = value;
|
|
6167
|
-
let optionSelectedStateSetter;
|
|
6168
|
-
if (Array.isArray(value)) {
|
|
6169
|
-
// convert values to ids
|
|
6170
|
-
const ids = value.map((v) => this._getOptionId(v));
|
|
6171
|
-
optionSelectedStateSetter = (opt, o) => {
|
|
6172
|
-
opt._setSelected(ids.indexOf(o.toString()) > -1);
|
|
6173
|
-
};
|
|
6174
|
-
}
|
|
6175
|
-
else {
|
|
6176
|
-
optionSelectedStateSetter = (opt, o) => {
|
|
6177
|
-
opt._setSelected(false);
|
|
6178
|
-
};
|
|
6179
|
-
}
|
|
6180
|
-
this._optionMap.forEach(optionSelectedStateSetter);
|
|
6181
|
-
}
|
|
6182
|
-
/**
|
|
6183
|
-
* Registers a function called when the control value changes
|
|
6184
|
-
* and writes an array of the selected options.
|
|
6185
|
-
* @docs-private
|
|
5913
|
+
* Tracks the name of the `FormGroup` bound to the directive. The name corresponds
|
|
5914
|
+
* to a key in the parent `FormGroup` or `FormArray`.
|
|
5915
|
+
* Accepts a name as a string or a number.
|
|
5916
|
+
* The name in the form of a string is useful for individual forms,
|
|
5917
|
+
* while the numerical form allows for form groups to be bound
|
|
5918
|
+
* to indices when iterating over groups in a `FormArray`.
|
|
6186
5919
|
*/
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
for (let i = 0; i < options.length; i++) {
|
|
6194
|
-
const opt = options[i];
|
|
6195
|
-
const val = this._getOptionValue(opt.value);
|
|
6196
|
-
selected.push(val);
|
|
6197
|
-
}
|
|
6198
|
-
}
|
|
6199
|
-
// Degrade to use `options` when `selectedOptions` property is not available.
|
|
6200
|
-
// Note: the `selectedOptions` is available in all supported browsers, but the Domino lib
|
|
6201
|
-
// doesn't have it currently, see https://github.com/fgnass/domino/issues/177.
|
|
6202
|
-
else {
|
|
6203
|
-
const options = element.options;
|
|
6204
|
-
for (let i = 0; i < options.length; i++) {
|
|
6205
|
-
const opt = options[i];
|
|
6206
|
-
if (opt.selected) {
|
|
6207
|
-
const val = this._getOptionValue(opt.value);
|
|
6208
|
-
selected.push(val);
|
|
6209
|
-
}
|
|
6210
|
-
}
|
|
6211
|
-
}
|
|
6212
|
-
this.value = selected;
|
|
6213
|
-
fn(selected);
|
|
6214
|
-
};
|
|
6215
|
-
}
|
|
6216
|
-
/** @internal */
|
|
6217
|
-
_registerOption(value) {
|
|
6218
|
-
const id = (this._idCounter++).toString();
|
|
6219
|
-
this._optionMap.set(id, value);
|
|
6220
|
-
return id;
|
|
5920
|
+
name = null;
|
|
5921
|
+
constructor(parent, validators, asyncValidators) {
|
|
5922
|
+
super();
|
|
5923
|
+
this._parent = parent;
|
|
5924
|
+
this._setValidators(validators);
|
|
5925
|
+
this._setAsyncValidators(asyncValidators);
|
|
6221
5926
|
}
|
|
6222
5927
|
/** @internal */
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
return id;
|
|
5928
|
+
_checkParentType() {
|
|
5929
|
+
if (hasInvalidParent(this._parent) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
5930
|
+
throw groupParentException();
|
|
6227
5931
|
}
|
|
6228
|
-
return null;
|
|
6229
5932
|
}
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
const id = _extractId(valueString);
|
|
6233
|
-
return this._optionMap.has(id) ? this._optionMap.get(id)._value : valueString;
|
|
6234
|
-
}
|
|
6235
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: SelectMultipleControlValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
6236
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: SelectMultipleControlValueAccessor, isStandalone: false, selector: "select[multiple][formControlName],select[multiple][formControl],select[multiple][ngModel]", inputs: { compareWith: "compareWith" }, host: { listeners: { "change": "onChange($event.target)", "blur": "onTouched()" } }, providers: [SELECT_MULTIPLE_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 });
|
|
5933
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormGroupName, deps: [{ token: ControlContainer, host: true, optional: true, skipSelf: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
5934
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: FormGroupName, isStandalone: false, selector: "[formGroupName]", inputs: { name: ["formGroupName", "name"] }, providers: [formGroupNameProvider], usesInheritance: true, ngImport: i0 });
|
|
6237
5935
|
}
|
|
6238
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
5936
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormGroupName, decorators: [{
|
|
6239
5937
|
type: Directive,
|
|
6240
5938
|
args: [{
|
|
6241
|
-
selector: '
|
|
6242
|
-
|
|
6243
|
-
providers: [SELECT_MULTIPLE_VALUE_ACCESSOR],
|
|
5939
|
+
selector: '[formGroupName]',
|
|
5940
|
+
providers: [formGroupNameProvider],
|
|
6244
5941
|
standalone: false,
|
|
6245
5942
|
}]
|
|
6246
|
-
}],
|
|
6247
|
-
|
|
5943
|
+
}], ctorParameters: () => [{ type: ControlContainer, decorators: [{
|
|
5944
|
+
type: Optional
|
|
5945
|
+
}, {
|
|
5946
|
+
type: Host
|
|
5947
|
+
}, {
|
|
5948
|
+
type: SkipSelf
|
|
5949
|
+
}] }, { type: undefined, decorators: [{
|
|
5950
|
+
type: Optional
|
|
5951
|
+
}, {
|
|
5952
|
+
type: Self
|
|
5953
|
+
}, {
|
|
5954
|
+
type: Inject,
|
|
5955
|
+
args: [NG_VALIDATORS]
|
|
5956
|
+
}] }, { type: undefined, decorators: [{
|
|
5957
|
+
type: Optional
|
|
5958
|
+
}, {
|
|
5959
|
+
type: Self
|
|
5960
|
+
}, {
|
|
5961
|
+
type: Inject,
|
|
5962
|
+
args: [NG_ASYNC_VALIDATORS]
|
|
5963
|
+
}] }], propDecorators: { name: [{
|
|
5964
|
+
type: Input,
|
|
5965
|
+
args: ['formGroupName']
|
|
6248
5966
|
}] } });
|
|
5967
|
+
const formArrayNameProvider = {
|
|
5968
|
+
provide: ControlContainer,
|
|
5969
|
+
useExisting: forwardRef(() => FormArrayName),
|
|
5970
|
+
};
|
|
6249
5971
|
/**
|
|
6250
5972
|
* @description
|
|
6251
|
-
* Marks `<option>` as dynamic, so Angular can be notified when options change.
|
|
6252
5973
|
*
|
|
6253
|
-
*
|
|
5974
|
+
* Syncs a nested `FormArray` to a DOM element.
|
|
5975
|
+
*
|
|
5976
|
+
* This directive is designed to be used with a parent `FormGroupDirective`/`FormGroupArray` (selector:
|
|
5977
|
+
* `[formGroup]`/`[formArray]`).
|
|
5978
|
+
*
|
|
5979
|
+
* It accepts the string name of the nested `FormArray` you want to link, and
|
|
5980
|
+
* will look for a `FormArray` registered with that name in the parent
|
|
5981
|
+
* `FormGroup`/`FormArray` instance you passed into `FormGroupDirective`/`FormGroupArray`.
|
|
5982
|
+
*
|
|
5983
|
+
* @see [Reactive Forms Guide](guide/forms/reactive-forms)
|
|
5984
|
+
* @see {@link AbstractControl}
|
|
5985
|
+
*
|
|
5986
|
+
* @usageNotes
|
|
5987
|
+
*
|
|
5988
|
+
* ### Example
|
|
5989
|
+
*
|
|
5990
|
+
* {@example forms/ts/nestedFormArray/nested_form_array_example.ts region='Component'}
|
|
6254
5991
|
*
|
|
6255
5992
|
* @ngModule ReactiveFormsModule
|
|
6256
|
-
* @ngModule FormsModule
|
|
6257
5993
|
* @publicApi
|
|
6258
5994
|
*/
|
|
6259
|
-
class
|
|
6260
|
-
_element;
|
|
6261
|
-
_renderer;
|
|
6262
|
-
_select;
|
|
6263
|
-
id;
|
|
5995
|
+
class FormArrayName extends ControlContainer {
|
|
6264
5996
|
/** @internal */
|
|
6265
|
-
|
|
6266
|
-
constructor(_element, _renderer, _select) {
|
|
6267
|
-
this._element = _element;
|
|
6268
|
-
this._renderer = _renderer;
|
|
6269
|
-
this._select = _select;
|
|
6270
|
-
if (this._select) {
|
|
6271
|
-
this.id = this._select._registerOption(this);
|
|
6272
|
-
}
|
|
6273
|
-
}
|
|
5997
|
+
_parent;
|
|
6274
5998
|
/**
|
|
6275
5999
|
* @description
|
|
6276
|
-
* Tracks the
|
|
6277
|
-
*
|
|
6000
|
+
* Tracks the name of the `FormArray` bound to the directive. The name corresponds
|
|
6001
|
+
* to a key in the parent `FormGroup` or `FormArray`.
|
|
6002
|
+
* Accepts a name as a string or a number.
|
|
6003
|
+
* The name in the form of a string is useful for individual forms,
|
|
6004
|
+
* while the numerical form allows for form arrays to be bound
|
|
6005
|
+
* to indices when iterating over arrays in a `FormArray`.
|
|
6278
6006
|
*/
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
this.
|
|
6283
|
-
this.
|
|
6284
|
-
this.
|
|
6007
|
+
name = null;
|
|
6008
|
+
constructor(parent, validators, asyncValidators) {
|
|
6009
|
+
super();
|
|
6010
|
+
this._parent = parent;
|
|
6011
|
+
this._setValidators(validators);
|
|
6012
|
+
this._setAsyncValidators(asyncValidators);
|
|
6285
6013
|
}
|
|
6286
6014
|
/**
|
|
6287
|
-
*
|
|
6288
|
-
*
|
|
6289
|
-
*
|
|
6015
|
+
* A lifecycle method called when the directive's inputs are initialized. For internal use only.
|
|
6016
|
+
* @throws If the directive does not have a valid parent.
|
|
6017
|
+
* @docs-private
|
|
6290
6018
|
*/
|
|
6291
|
-
|
|
6292
|
-
if (this.
|
|
6293
|
-
|
|
6294
|
-
this._setElementValue(_buildValueString(this.id, value));
|
|
6295
|
-
this._select.writeValue(this._select.value);
|
|
6296
|
-
}
|
|
6297
|
-
else {
|
|
6298
|
-
this._setElementValue(value);
|
|
6019
|
+
ngOnInit() {
|
|
6020
|
+
if (hasInvalidParent(this._parent) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
6021
|
+
throw arrayParentException();
|
|
6299
6022
|
}
|
|
6023
|
+
this.formDirective.addFormArray(this);
|
|
6300
6024
|
}
|
|
6301
|
-
/**
|
|
6302
|
-
|
|
6303
|
-
|
|
6025
|
+
/**
|
|
6026
|
+
* A lifecycle method called before the directive's instance is destroyed. For internal use only.
|
|
6027
|
+
* @docs-private
|
|
6028
|
+
*/
|
|
6029
|
+
ngOnDestroy() {
|
|
6030
|
+
this.formDirective?.removeFormArray(this);
|
|
6304
6031
|
}
|
|
6305
|
-
/**
|
|
6306
|
-
|
|
6307
|
-
|
|
6032
|
+
/**
|
|
6033
|
+
* @description
|
|
6034
|
+
* The `FormArray` bound to this directive.
|
|
6035
|
+
*/
|
|
6036
|
+
get control() {
|
|
6037
|
+
return this.formDirective.getFormArray(this);
|
|
6308
6038
|
}
|
|
6309
|
-
/**
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6039
|
+
/**
|
|
6040
|
+
* @description
|
|
6041
|
+
* The top-level directive for this group if present, otherwise null.
|
|
6042
|
+
*/
|
|
6043
|
+
get formDirective() {
|
|
6044
|
+
return this._parent ? this._parent.formDirective : null;
|
|
6315
6045
|
}
|
|
6316
|
-
|
|
6317
|
-
|
|
6046
|
+
/**
|
|
6047
|
+
* @description
|
|
6048
|
+
* Returns an array that represents the path from the top-level form to this control.
|
|
6049
|
+
* Each index is the string name of the control on that level.
|
|
6050
|
+
*/
|
|
6051
|
+
get path() {
|
|
6052
|
+
return controlPath(this.name == null ? this.name : this.name.toString(), this._parent);
|
|
6053
|
+
}
|
|
6054
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormArrayName, deps: [{ token: ControlContainer, host: true, optional: true, skipSelf: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
6055
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: FormArrayName, isStandalone: false, selector: "[formArrayName]", inputs: { name: ["formArrayName", "name"] }, providers: [formArrayNameProvider], usesInheritance: true, ngImport: i0 });
|
|
6318
6056
|
}
|
|
6319
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
6057
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormArrayName, decorators: [{
|
|
6320
6058
|
type: Directive,
|
|
6321
6059
|
args: [{
|
|
6322
|
-
selector: '
|
|
6060
|
+
selector: '[formArrayName]',
|
|
6061
|
+
providers: [formArrayNameProvider],
|
|
6323
6062
|
standalone: false,
|
|
6324
6063
|
}]
|
|
6325
|
-
}], ctorParameters: () => [{ type:
|
|
6064
|
+
}], ctorParameters: () => [{ type: ControlContainer, decorators: [{
|
|
6326
6065
|
type: Optional
|
|
6327
6066
|
}, {
|
|
6328
6067
|
type: Host
|
|
6329
|
-
}
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6068
|
+
}, {
|
|
6069
|
+
type: SkipSelf
|
|
6070
|
+
}] }, { type: undefined, decorators: [{
|
|
6071
|
+
type: Optional
|
|
6072
|
+
}, {
|
|
6073
|
+
type: Self
|
|
6074
|
+
}, {
|
|
6075
|
+
type: Inject,
|
|
6076
|
+
args: [NG_VALIDATORS]
|
|
6077
|
+
}] }, { type: undefined, decorators: [{
|
|
6078
|
+
type: Optional
|
|
6079
|
+
}, {
|
|
6080
|
+
type: Self
|
|
6081
|
+
}, {
|
|
6082
|
+
type: Inject,
|
|
6083
|
+
args: [NG_ASYNC_VALIDATORS]
|
|
6084
|
+
}] }], propDecorators: { name: [{
|
|
6333
6085
|
type: Input,
|
|
6334
|
-
args: ['
|
|
6086
|
+
args: ['formArrayName']
|
|
6335
6087
|
}] } });
|
|
6088
|
+
function hasInvalidParent(parent) {
|
|
6089
|
+
return (!(parent instanceof FormGroupName) &&
|
|
6090
|
+
!(parent instanceof AbstractFormDirective) &&
|
|
6091
|
+
!(parent instanceof FormArrayName));
|
|
6092
|
+
}
|
|
6336
6093
|
|
|
6094
|
+
const controlNameBinding = {
|
|
6095
|
+
provide: NgControl,
|
|
6096
|
+
useExisting: forwardRef(() => FormControlName),
|
|
6097
|
+
};
|
|
6337
6098
|
/**
|
|
6338
|
-
*
|
|
6099
|
+
* @description
|
|
6100
|
+
* Syncs a `FormControl` in an existing `FormGroup` to a form control
|
|
6101
|
+
* element by name.
|
|
6339
6102
|
*
|
|
6340
|
-
* @
|
|
6341
|
-
* @
|
|
6342
|
-
|
|
6343
|
-
function toInteger(value) {
|
|
6344
|
-
return typeof value === 'number' ? value : parseInt(value, 10);
|
|
6345
|
-
}
|
|
6346
|
-
/**
|
|
6347
|
-
* Method that ensures that provided value is a float (and converts it to float if needed).
|
|
6103
|
+
* @see [Reactive Forms Guide](guide/forms/reactive-forms)
|
|
6104
|
+
* @see {@link FormControl}
|
|
6105
|
+
* @see {@link AbstractControl}
|
|
6348
6106
|
*
|
|
6349
|
-
* @
|
|
6350
|
-
* @returns value of parameter converted to number or float.
|
|
6351
|
-
*/
|
|
6352
|
-
function toFloat(value) {
|
|
6353
|
-
return typeof value === 'number' ? value : parseFloat(value);
|
|
6354
|
-
}
|
|
6355
|
-
/**
|
|
6356
|
-
* A base class for Validator-based Directives. The class contains common logic shared across such
|
|
6357
|
-
* Directives.
|
|
6107
|
+
* @usageNotes
|
|
6358
6108
|
*
|
|
6359
|
-
*
|
|
6109
|
+
* ### Register `FormControl` within a group
|
|
6110
|
+
*
|
|
6111
|
+
* The following example shows how to register multiple form controls within a form group
|
|
6112
|
+
* and set their value.
|
|
6113
|
+
*
|
|
6114
|
+
* {@example forms/ts/simpleFormGroup/simple_form_group_example.ts region='Component'}
|
|
6115
|
+
*
|
|
6116
|
+
* To see `formControlName` examples with different form control types, see:
|
|
6117
|
+
*
|
|
6118
|
+
* * Radio buttons: `RadioControlValueAccessor`
|
|
6119
|
+
* * Selects: `SelectControlValueAccessor`
|
|
6120
|
+
*
|
|
6121
|
+
* ### Use with ngModel is deprecated
|
|
6122
|
+
*
|
|
6123
|
+
* Support for using the `ngModel` input property and `ngModelChange` event with reactive
|
|
6124
|
+
* form directives has been deprecated in Angular v6 and is scheduled for removal in
|
|
6125
|
+
* a future version of Angular.
|
|
6126
|
+
*
|
|
6127
|
+
* @ngModule ReactiveFormsModule
|
|
6128
|
+
* @publicApi
|
|
6360
6129
|
*/
|
|
6361
|
-
class
|
|
6362
|
-
|
|
6363
|
-
|
|
6130
|
+
class FormControlName extends NgControl {
|
|
6131
|
+
_ngModelWarningConfig;
|
|
6132
|
+
_added = false;
|
|
6364
6133
|
/**
|
|
6365
|
-
*
|
|
6134
|
+
* Internal reference to the view model value.
|
|
6135
|
+
* @internal
|
|
6136
|
+
*/
|
|
6137
|
+
viewModel;
|
|
6138
|
+
/**
|
|
6139
|
+
* @description
|
|
6140
|
+
* Tracks the `FormControl` instance bound to the directive.
|
|
6141
|
+
*/
|
|
6142
|
+
control;
|
|
6143
|
+
/**
|
|
6144
|
+
* @description
|
|
6145
|
+
* Tracks the name of the `FormControl` bound to the directive. The name corresponds
|
|
6146
|
+
* to a key in the parent `FormGroup` or `FormArray`.
|
|
6147
|
+
* Accepts a name as a string or a number.
|
|
6148
|
+
* The name in the form of a string is useful for individual forms,
|
|
6149
|
+
* while the numerical form allows for form controls to be bound
|
|
6150
|
+
* to indices when iterating over controls in a `FormArray`.
|
|
6151
|
+
*/
|
|
6152
|
+
name = null;
|
|
6153
|
+
/**
|
|
6154
|
+
* @description
|
|
6155
|
+
* Triggers a warning in dev mode that this input should not be used with reactive forms.
|
|
6156
|
+
*/
|
|
6157
|
+
set isDisabled(isDisabled) {
|
|
6158
|
+
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
6159
|
+
console.warn(disabledAttrWarning);
|
|
6160
|
+
}
|
|
6161
|
+
}
|
|
6162
|
+
// TODO(kara): remove next 4 properties once deprecation period is over
|
|
6163
|
+
/** @deprecated as of v6 */
|
|
6164
|
+
model;
|
|
6165
|
+
/** @deprecated as of v6 */
|
|
6166
|
+
update = new EventEmitter();
|
|
6167
|
+
/**
|
|
6168
|
+
* @description
|
|
6169
|
+
* Static property used to track whether any ngModel warnings have been sent across
|
|
6170
|
+
* all instances of FormControlName. Used to support warning config of "once".
|
|
6366
6171
|
*
|
|
6367
|
-
* Marking it `internal` (vs `protected`), so that this flag can be used in host bindings of
|
|
6368
|
-
* directive classes that extend this base class.
|
|
6369
6172
|
* @internal
|
|
6370
6173
|
*/
|
|
6371
|
-
|
|
6174
|
+
static _ngModelWarningSentOnce = false;
|
|
6175
|
+
/**
|
|
6176
|
+
* @description
|
|
6177
|
+
* Instance property used to track whether an ngModel warning has been sent out for this
|
|
6178
|
+
* particular FormControlName instance. Used to support warning config of "always".
|
|
6179
|
+
*
|
|
6180
|
+
* @internal
|
|
6181
|
+
*/
|
|
6182
|
+
_ngModelWarningSent = false;
|
|
6183
|
+
constructor(parent, validators, asyncValidators, valueAccessors, _ngModelWarningConfig) {
|
|
6184
|
+
super();
|
|
6185
|
+
this._ngModelWarningConfig = _ngModelWarningConfig;
|
|
6186
|
+
this._parent = parent;
|
|
6187
|
+
this._setValidators(validators);
|
|
6188
|
+
this._setAsyncValidators(asyncValidators);
|
|
6189
|
+
this.valueAccessor = selectValueAccessor(this, valueAccessors);
|
|
6190
|
+
}
|
|
6372
6191
|
/** @docs-private */
|
|
6373
6192
|
ngOnChanges(changes) {
|
|
6374
|
-
if (this.
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
|
|
6379
|
-
this._onChange();
|
|
6193
|
+
if (!this._added)
|
|
6194
|
+
this._setUpControl();
|
|
6195
|
+
if (isPropertyUpdated(changes, this.viewModel)) {
|
|
6196
|
+
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
6197
|
+
_ngModelWarning('formControlName', FormControlName, this, this._ngModelWarningConfig);
|
|
6380
6198
|
}
|
|
6199
|
+
this.viewModel = this.model;
|
|
6200
|
+
this.formDirective.updateModel(this, this.model);
|
|
6381
6201
|
}
|
|
6382
6202
|
}
|
|
6383
6203
|
/** @docs-private */
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
registerOnValidatorChange(fn) {
|
|
6389
|
-
this._onChange = fn;
|
|
6204
|
+
ngOnDestroy() {
|
|
6205
|
+
if (this.formDirective) {
|
|
6206
|
+
this.formDirective.removeControl(this);
|
|
6207
|
+
}
|
|
6390
6208
|
}
|
|
6391
6209
|
/**
|
|
6392
6210
|
* @description
|
|
6393
|
-
*
|
|
6394
|
-
*
|
|
6395
|
-
*
|
|
6396
|
-
* function with the logic specific to a particular validator directive.
|
|
6211
|
+
* Sets the new value for the view model and emits an `ngModelChange` event.
|
|
6212
|
+
*
|
|
6213
|
+
* @param newValue The new value for the view model.
|
|
6397
6214
|
*/
|
|
6398
|
-
|
|
6399
|
-
|
|
6215
|
+
viewToModelUpdate(newValue) {
|
|
6216
|
+
this.viewModel = newValue;
|
|
6217
|
+
this.update.emit(newValue);
|
|
6400
6218
|
}
|
|
6401
|
-
|
|
6402
|
-
|
|
6219
|
+
/**
|
|
6220
|
+
* @description
|
|
6221
|
+
* Returns an array that represents the path from the top-level form to this control.
|
|
6222
|
+
* Each index is the string name of the control on that level.
|
|
6223
|
+
*/
|
|
6224
|
+
get path() {
|
|
6225
|
+
return controlPath(this.name == null ? this.name : this.name.toString(), this._parent);
|
|
6226
|
+
}
|
|
6227
|
+
/**
|
|
6228
|
+
* @description
|
|
6229
|
+
* The top-level directive for this group if present, otherwise null.
|
|
6230
|
+
*/
|
|
6231
|
+
get formDirective() {
|
|
6232
|
+
return this._parent ? this._parent.formDirective : null;
|
|
6233
|
+
}
|
|
6234
|
+
_setUpControl() {
|
|
6235
|
+
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
6236
|
+
checkParentType(this._parent, this.name);
|
|
6237
|
+
}
|
|
6238
|
+
this.control = this.formDirective.addControl(this);
|
|
6239
|
+
this._added = true;
|
|
6240
|
+
}
|
|
6241
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormControlName, deps: [{ token: ControlContainer, host: true, optional: true, skipSelf: true }, { token: NG_VALIDATORS, optional: true, self: true }, { token: NG_ASYNC_VALIDATORS, optional: true, self: true }, { token: NG_VALUE_ACCESSOR, optional: true, self: true }, { token: NG_MODEL_WITH_FORM_CONTROL_WARNING, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
6242
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: FormControlName, isStandalone: false, selector: "[formControlName]", inputs: { name: ["formControlName", "name"], isDisabled: ["disabled", "isDisabled"], model: ["ngModel", "model"] }, outputs: { update: "ngModelChange" }, providers: [controlNameBinding], usesInheritance: true, usesOnChanges: true, ngImport: i0 });
|
|
6403
6243
|
}
|
|
6404
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
6405
|
-
type: Directive
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
|
|
6244
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormControlName, decorators: [{
|
|
6245
|
+
type: Directive,
|
|
6246
|
+
args: [{
|
|
6247
|
+
selector: '[formControlName]',
|
|
6248
|
+
providers: [controlNameBinding],
|
|
6249
|
+
standalone: false,
|
|
6250
|
+
}]
|
|
6251
|
+
}], ctorParameters: () => [{ type: ControlContainer, decorators: [{
|
|
6252
|
+
type: Optional
|
|
6253
|
+
}, {
|
|
6254
|
+
type: Host
|
|
6255
|
+
}, {
|
|
6256
|
+
type: SkipSelf
|
|
6257
|
+
}] }, { type: undefined, decorators: [{
|
|
6258
|
+
type: Optional
|
|
6259
|
+
}, {
|
|
6260
|
+
type: Self
|
|
6261
|
+
}, {
|
|
6262
|
+
type: Inject,
|
|
6263
|
+
args: [NG_VALIDATORS]
|
|
6264
|
+
}] }, { type: undefined, decorators: [{
|
|
6265
|
+
type: Optional
|
|
6266
|
+
}, {
|
|
6267
|
+
type: Self
|
|
6268
|
+
}, {
|
|
6269
|
+
type: Inject,
|
|
6270
|
+
args: [NG_ASYNC_VALIDATORS]
|
|
6271
|
+
}] }, { type: undefined, decorators: [{
|
|
6272
|
+
type: Optional
|
|
6273
|
+
}, {
|
|
6274
|
+
type: Self
|
|
6275
|
+
}, {
|
|
6276
|
+
type: Inject,
|
|
6277
|
+
args: [NG_VALUE_ACCESSOR]
|
|
6278
|
+
}] }, { type: undefined, decorators: [{
|
|
6279
|
+
type: Optional
|
|
6280
|
+
}, {
|
|
6281
|
+
type: Inject,
|
|
6282
|
+
args: [NG_MODEL_WITH_FORM_CONTROL_WARNING]
|
|
6283
|
+
}] }], propDecorators: { name: [{
|
|
6284
|
+
type: Input,
|
|
6285
|
+
args: ['formControlName']
|
|
6286
|
+
}], isDisabled: [{
|
|
6287
|
+
type: Input,
|
|
6288
|
+
args: ['disabled']
|
|
6289
|
+
}], model: [{
|
|
6290
|
+
type: Input,
|
|
6291
|
+
args: ['ngModel']
|
|
6292
|
+
}], update: [{
|
|
6293
|
+
type: Output,
|
|
6294
|
+
args: ['ngModelChange']
|
|
6295
|
+
}] } });
|
|
6296
|
+
function checkParentType(parent, name) {
|
|
6297
|
+
if (!(parent instanceof FormGroupName) && parent instanceof AbstractFormGroupDirective) {
|
|
6298
|
+
throw ngModelGroupException();
|
|
6299
|
+
}
|
|
6300
|
+
else if (!(parent instanceof FormGroupName) &&
|
|
6301
|
+
!(parent instanceof AbstractFormDirective) &&
|
|
6302
|
+
!(parent instanceof FormArrayName)) {
|
|
6303
|
+
throw controlParentException(name);
|
|
6304
|
+
}
|
|
6305
|
+
}
|
|
6306
|
+
|
|
6307
|
+
const formDirectiveProvider = {
|
|
6308
|
+
provide: ControlContainer,
|
|
6309
|
+
useExisting: forwardRef(() => FormGroupDirective),
|
|
6415
6310
|
};
|
|
6416
6311
|
/**
|
|
6417
|
-
*
|
|
6418
|
-
* `formControl`, or control with `ngModel` that also has a `max` attribute.
|
|
6312
|
+
* @description
|
|
6419
6313
|
*
|
|
6420
|
-
*
|
|
6314
|
+
* Binds an existing `FormGroup` or `FormRecord` to a DOM element.
|
|
6421
6315
|
*
|
|
6422
|
-
*
|
|
6316
|
+
* This directive accepts an existing `FormGroup` instance. It will then use this
|
|
6317
|
+
* `FormGroup` instance to match any child `FormControl`, `FormGroup`/`FormRecord`,
|
|
6318
|
+
* and `FormArray` instances to child `FormControlName`, `FormGroupName`,
|
|
6319
|
+
* and `FormArrayName` directives.
|
|
6423
6320
|
*
|
|
6424
|
-
*
|
|
6321
|
+
* @see [Reactive Forms Guide](guide/forms/reactive-forms)
|
|
6322
|
+
* @see {@link AbstractControl}
|
|
6425
6323
|
*
|
|
6426
|
-
*
|
|
6427
|
-
*
|
|
6324
|
+
* @usageNotes
|
|
6325
|
+
* ### Register Form Group
|
|
6428
6326
|
*
|
|
6429
|
-
*
|
|
6430
|
-
*
|
|
6431
|
-
*
|
|
6327
|
+
* The following example registers a `FormGroup` with first name and last name controls,
|
|
6328
|
+
* and listens for the *ngSubmit* event when the button is clicked.
|
|
6329
|
+
*
|
|
6330
|
+
* {@example forms/ts/simpleFormGroup/simple_form_group_example.ts region='Component'}
|
|
6432
6331
|
*
|
|
6433
6332
|
* @ngModule ReactiveFormsModule
|
|
6434
|
-
* @ngModule FormsModule
|
|
6435
6333
|
* @publicApi
|
|
6436
6334
|
*/
|
|
6437
|
-
class
|
|
6335
|
+
class FormGroupDirective extends AbstractFormDirective {
|
|
6438
6336
|
/**
|
|
6439
6337
|
* @description
|
|
6440
|
-
* Tracks
|
|
6338
|
+
* Tracks the `FormGroup` bound to this directive.
|
|
6441
6339
|
*/
|
|
6442
|
-
|
|
6443
|
-
/**
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6340
|
+
form = null;
|
|
6341
|
+
/**
|
|
6342
|
+
* @description
|
|
6343
|
+
* Emits an event when the form submission has been triggered.
|
|
6344
|
+
*/
|
|
6345
|
+
ngSubmit = new EventEmitter();
|
|
6346
|
+
/**
|
|
6347
|
+
* @description
|
|
6348
|
+
* Returns the `FormGroup` bound to this directive.
|
|
6349
|
+
*/
|
|
6350
|
+
get control() {
|
|
6351
|
+
return this.form;
|
|
6352
|
+
}
|
|
6353
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormGroupDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
6354
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: FormGroupDirective, isStandalone: false, selector: "[formGroup]", inputs: { form: ["formGroup", "form"] }, outputs: { ngSubmit: "ngSubmit" }, host: { listeners: { "submit": "onSubmit($event)", "reset": "onReset()" } }, providers: [formDirectiveProvider], exportAs: ["ngForm"], usesInheritance: true, ngImport: i0 });
|
|
6451
6355
|
}
|
|
6452
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
6356
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FormGroupDirective, decorators: [{
|
|
6453
6357
|
type: Directive,
|
|
6454
6358
|
args: [{
|
|
6455
|
-
selector: '
|
|
6456
|
-
providers: [
|
|
6457
|
-
host: { '
|
|
6359
|
+
selector: '[formGroup]',
|
|
6360
|
+
providers: [formDirectiveProvider],
|
|
6361
|
+
host: { '(submit)': 'onSubmit($event)', '(reset)': 'onReset()' },
|
|
6362
|
+
exportAs: 'ngForm',
|
|
6458
6363
|
standalone: false,
|
|
6459
6364
|
}]
|
|
6460
|
-
}], propDecorators: {
|
|
6461
|
-
type: Input
|
|
6365
|
+
}], propDecorators: { form: [{
|
|
6366
|
+
type: Input,
|
|
6367
|
+
args: ['formGroup']
|
|
6368
|
+
}], ngSubmit: [{
|
|
6369
|
+
type: Output
|
|
6462
6370
|
}] } });
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
const MIN_VALIDATOR = {
|
|
6468
|
-
provide: NG_VALIDATORS,
|
|
6469
|
-
useExisting: forwardRef(() => MinValidator),
|
|
6371
|
+
|
|
6372
|
+
const SELECT_VALUE_ACCESSOR = {
|
|
6373
|
+
provide: NG_VALUE_ACCESSOR,
|
|
6374
|
+
useExisting: forwardRef(() => SelectControlValueAccessor),
|
|
6470
6375
|
multi: true,
|
|
6471
6376
|
};
|
|
6377
|
+
function _buildValueString$1(id, value) {
|
|
6378
|
+
if (id == null)
|
|
6379
|
+
return `${value}`;
|
|
6380
|
+
if (value && typeof value === 'object')
|
|
6381
|
+
value = 'Object';
|
|
6382
|
+
return `${id}: ${value}`.slice(0, 50);
|
|
6383
|
+
}
|
|
6384
|
+
function _extractId$1(valueString) {
|
|
6385
|
+
return valueString.split(':')[0];
|
|
6386
|
+
}
|
|
6472
6387
|
/**
|
|
6473
|
-
*
|
|
6474
|
-
* `
|
|
6475
|
-
*
|
|
6476
|
-
*
|
|
6388
|
+
* @description
|
|
6389
|
+
* The `ControlValueAccessor` for writing select control values and listening to select control
|
|
6390
|
+
* changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
|
|
6391
|
+
* `NgModel` directives.
|
|
6477
6392
|
*
|
|
6478
6393
|
* @usageNotes
|
|
6479
6394
|
*
|
|
6480
|
-
* ###
|
|
6395
|
+
* ### Using select controls in a reactive form
|
|
6481
6396
|
*
|
|
6482
|
-
* The following
|
|
6483
|
-
*
|
|
6397
|
+
* The following examples show how to use a select control in a reactive form.
|
|
6398
|
+
*
|
|
6399
|
+
* {@example forms/ts/reactiveSelectControl/reactive_select_control_example.ts region='Component'}
|
|
6400
|
+
*
|
|
6401
|
+
* ### Using select controls in a template-driven form
|
|
6402
|
+
*
|
|
6403
|
+
* To use a select in a template-driven form, simply add an `ngModel` and a `name`
|
|
6404
|
+
* attribute to the main `<select>` tag.
|
|
6405
|
+
*
|
|
6406
|
+
* {@example forms/ts/selectControl/select_control_example.ts region='Component'}
|
|
6407
|
+
*
|
|
6408
|
+
* ### Customizing option selection
|
|
6409
|
+
*
|
|
6410
|
+
* Angular uses object identity to select option. It's possible for the identities of items
|
|
6411
|
+
* to change while the data does not. This can happen, for example, if the items are produced
|
|
6412
|
+
* from an RPC to the server, and that RPC is re-run. Even if the data hasn't changed, the
|
|
6413
|
+
* second response will produce objects with different identities.
|
|
6414
|
+
*
|
|
6415
|
+
* To customize the default option comparison algorithm, `<select>` supports `compareWith` input.
|
|
6416
|
+
* `compareWith` takes a **function** which has two arguments: `option1` and `option2`.
|
|
6417
|
+
* If `compareWith` is given, Angular selects option by the return value of the function.
|
|
6418
|
+
*
|
|
6419
|
+
* ```ts
|
|
6420
|
+
* const selectedCountriesControl = new FormControl();
|
|
6421
|
+
* ```
|
|
6484
6422
|
*
|
|
6485
6423
|
* ```html
|
|
6486
|
-
* <
|
|
6424
|
+
* <select [compareWith]="compareFn" [formControl]="selectedCountriesControl">
|
|
6425
|
+
* @for(country of countries; track $index) {
|
|
6426
|
+
* <option[ngValue]="country">{{country.name}}</option>
|
|
6427
|
+
* }
|
|
6428
|
+
* </select>
|
|
6429
|
+
*
|
|
6430
|
+
* compareFn(c1: Country, c2: Country): boolean {
|
|
6431
|
+
* return c1 && c2 ? c1.id === c2.id : c1 === c2;
|
|
6432
|
+
* }
|
|
6487
6433
|
* ```
|
|
6488
6434
|
*
|
|
6435
|
+
* **Note:** We listen to the 'change' event because 'input' events aren't fired
|
|
6436
|
+
* for selects in IE, see:
|
|
6437
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event#browser_compatibility
|
|
6438
|
+
*
|
|
6489
6439
|
* @ngModule ReactiveFormsModule
|
|
6490
6440
|
* @ngModule FormsModule
|
|
6491
6441
|
* @publicApi
|
|
6492
6442
|
*/
|
|
6493
|
-
class
|
|
6443
|
+
class SelectControlValueAccessor extends BuiltInControlValueAccessor {
|
|
6444
|
+
/** @docs-private */
|
|
6445
|
+
value;
|
|
6446
|
+
/** @internal */
|
|
6447
|
+
_optionMap = new Map();
|
|
6448
|
+
/** @internal */
|
|
6449
|
+
_idCounter = 0;
|
|
6494
6450
|
/**
|
|
6495
6451
|
* @description
|
|
6496
|
-
* Tracks
|
|
6452
|
+
* Tracks the option comparison algorithm for tracking identities when
|
|
6453
|
+
* checking for changes.
|
|
6497
6454
|
*/
|
|
6498
|
-
|
|
6455
|
+
set compareWith(fn) {
|
|
6456
|
+
if (typeof fn !== 'function' && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
6457
|
+
throw new _RuntimeError(1201 /* RuntimeErrorCode.COMPAREWITH_NOT_A_FN */, `compareWith must be a function, but received ${JSON.stringify(fn)}`);
|
|
6458
|
+
}
|
|
6459
|
+
this._compareWith = fn;
|
|
6460
|
+
}
|
|
6461
|
+
_compareWith = Object.is;
|
|
6462
|
+
// We need this because we might be in the process of destroying the root
|
|
6463
|
+
// injector, which is marked as destroyed before running destroy hooks.
|
|
6464
|
+
// Attempting to use afterNextRender with the node injector would evntually
|
|
6465
|
+
// run into that already destroyed injector.
|
|
6466
|
+
appRefInjector = inject(ApplicationRef).injector;
|
|
6467
|
+
destroyRef = inject(DestroyRef);
|
|
6468
|
+
cdr = inject(ChangeDetectorRef);
|
|
6469
|
+
_queuedWrite = false;
|
|
6470
|
+
/**
|
|
6471
|
+
* This is needed to efficiently set the select value when adding/removing options. If
|
|
6472
|
+
* writeValue is instead called for every added/removed option, this results in exponentially
|
|
6473
|
+
* more _compareValue calls than the number of option elements (issue #41330).
|
|
6474
|
+
*
|
|
6475
|
+
* Secondly, calling writeValue when rendering individual option elements instead of after they
|
|
6476
|
+
* are all rendered caused an issue in Safari and IE 11 where the first option element failed
|
|
6477
|
+
* to be deselected when no option matched the select ngModel. This was because Angular would
|
|
6478
|
+
* set the select element's value property before appending the option's child text node to the
|
|
6479
|
+
* DOM (issue #14505).
|
|
6480
|
+
*
|
|
6481
|
+
* Finally, this approach is necessary to avoid an issue with delayed element removal when
|
|
6482
|
+
* using the animations module (in all browsers). Otherwise when a selected option is removed
|
|
6483
|
+
* (so no option matches the ngModel anymore), Angular would change the select element value
|
|
6484
|
+
* before actually removing the option from the DOM. Then when the option is finally removed
|
|
6485
|
+
* from the DOM, the browser would change the select value to that of the first option, even
|
|
6486
|
+
* though it doesn't match the ngModel (issue #18430).
|
|
6487
|
+
*
|
|
6488
|
+
* @internal
|
|
6489
|
+
*/
|
|
6490
|
+
_writeValueAfterRender() {
|
|
6491
|
+
if (this._queuedWrite || this.appRefInjector.destroyed) {
|
|
6492
|
+
return;
|
|
6493
|
+
}
|
|
6494
|
+
this._queuedWrite = true;
|
|
6495
|
+
afterNextRender({
|
|
6496
|
+
write: () => {
|
|
6497
|
+
if (this.destroyRef.destroyed) {
|
|
6498
|
+
return;
|
|
6499
|
+
}
|
|
6500
|
+
this._queuedWrite = false;
|
|
6501
|
+
this.writeValue(this.value);
|
|
6502
|
+
},
|
|
6503
|
+
}, { injector: this.appRefInjector });
|
|
6504
|
+
}
|
|
6505
|
+
/**
|
|
6506
|
+
* Sets the "value" property on the select element.
|
|
6507
|
+
* @docs-private
|
|
6508
|
+
*/
|
|
6509
|
+
writeValue(value) {
|
|
6510
|
+
// TODO(atscott): This could likely be optimized more by only marking for check if the value is changed
|
|
6511
|
+
// note that this needs to include both the internal value and the value in the DOM.
|
|
6512
|
+
this.cdr.markForCheck();
|
|
6513
|
+
this.value = value;
|
|
6514
|
+
const id = this._getOptionId(value);
|
|
6515
|
+
const valueString = _buildValueString$1(id, value);
|
|
6516
|
+
this.setProperty('value', valueString);
|
|
6517
|
+
}
|
|
6518
|
+
/**
|
|
6519
|
+
* Registers a function called when the control value changes.
|
|
6520
|
+
* @docs-private
|
|
6521
|
+
*/
|
|
6522
|
+
registerOnChange(fn) {
|
|
6523
|
+
this.onChange = (valueString) => {
|
|
6524
|
+
this.value = this._getOptionValue(valueString);
|
|
6525
|
+
fn(this.value);
|
|
6526
|
+
};
|
|
6527
|
+
}
|
|
6499
6528
|
/** @internal */
|
|
6500
|
-
|
|
6529
|
+
_registerOption() {
|
|
6530
|
+
return (this._idCounter++).toString();
|
|
6531
|
+
}
|
|
6501
6532
|
/** @internal */
|
|
6502
|
-
|
|
6533
|
+
_getOptionId(value) {
|
|
6534
|
+
for (const id of this._optionMap.keys()) {
|
|
6535
|
+
if (this._compareWith(this._optionMap.get(id), value))
|
|
6536
|
+
return id;
|
|
6537
|
+
}
|
|
6538
|
+
return null;
|
|
6539
|
+
}
|
|
6503
6540
|
/** @internal */
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6541
|
+
_getOptionValue(valueString) {
|
|
6542
|
+
const id = _extractId$1(valueString);
|
|
6543
|
+
return this._optionMap.has(id) ? this._optionMap.get(id) : valueString;
|
|
6544
|
+
}
|
|
6545
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: SelectControlValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
6546
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: SelectControlValueAccessor, isStandalone: false, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: { compareWith: "compareWith" }, host: { listeners: { "change": "onChange($any($event.target).value)", "blur": "onTouched()" } }, providers: [SELECT_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 });
|
|
6507
6547
|
}
|
|
6508
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
6548
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: SelectControlValueAccessor, decorators: [{
|
|
6509
6549
|
type: Directive,
|
|
6510
6550
|
args: [{
|
|
6511
|
-
selector: '
|
|
6512
|
-
|
|
6513
|
-
|
|
6551
|
+
selector: 'select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]',
|
|
6552
|
+
host: { '(change)': 'onChange($any($event.target).value)', '(blur)': 'onTouched()' },
|
|
6553
|
+
providers: [SELECT_VALUE_ACCESSOR],
|
|
6514
6554
|
standalone: false,
|
|
6515
6555
|
}]
|
|
6516
|
-
}], propDecorators: {
|
|
6556
|
+
}], propDecorators: { compareWith: [{
|
|
6517
6557
|
type: Input
|
|
6518
6558
|
}] } });
|
|
6519
6559
|
/**
|
|
6520
6560
|
* @description
|
|
6521
|
-
*
|
|
6522
|
-
*/
|
|
6523
|
-
const REQUIRED_VALIDATOR = {
|
|
6524
|
-
provide: NG_VALIDATORS,
|
|
6525
|
-
useExisting: forwardRef(() => RequiredValidator),
|
|
6526
|
-
multi: true,
|
|
6527
|
-
};
|
|
6528
|
-
/**
|
|
6529
|
-
* @description
|
|
6530
|
-
* Provider which adds `CheckboxRequiredValidator` to the `NG_VALIDATORS` multi-provider list.
|
|
6531
|
-
*/
|
|
6532
|
-
const CHECKBOX_REQUIRED_VALIDATOR = {
|
|
6533
|
-
provide: NG_VALIDATORS,
|
|
6534
|
-
useExisting: forwardRef(() => CheckboxRequiredValidator),
|
|
6535
|
-
multi: true,
|
|
6536
|
-
};
|
|
6537
|
-
/**
|
|
6538
|
-
* @description
|
|
6539
|
-
* A directive that adds the `required` validator to any controls marked with the
|
|
6540
|
-
* `required` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
|
6541
|
-
*
|
|
6542
|
-
* @see [Form Validation](guide/forms/form-validation)
|
|
6543
|
-
*
|
|
6544
|
-
* @usageNotes
|
|
6545
|
-
*
|
|
6546
|
-
* ### Adding a required validator using template-driven forms
|
|
6561
|
+
* Marks `<option>` as dynamic, so Angular can be notified when options change.
|
|
6547
6562
|
*
|
|
6548
|
-
*
|
|
6549
|
-
* <input name="fullName" ngModel required>
|
|
6550
|
-
* ```
|
|
6563
|
+
* @see {@link SelectControlValueAccessor}
|
|
6551
6564
|
*
|
|
6552
|
-
* @ngModule FormsModule
|
|
6553
6565
|
* @ngModule ReactiveFormsModule
|
|
6566
|
+
* @ngModule FormsModule
|
|
6554
6567
|
* @publicApi
|
|
6555
6568
|
*/
|
|
6556
|
-
class
|
|
6569
|
+
class NgSelectOption {
|
|
6570
|
+
_element;
|
|
6571
|
+
_renderer;
|
|
6572
|
+
_select;
|
|
6557
6573
|
/**
|
|
6558
6574
|
* @description
|
|
6559
|
-
*
|
|
6575
|
+
* ID of the option element
|
|
6560
6576
|
*/
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6577
|
+
id;
|
|
6578
|
+
constructor(_element, _renderer, _select) {
|
|
6579
|
+
this._element = _element;
|
|
6580
|
+
this._renderer = _renderer;
|
|
6581
|
+
this._select = _select;
|
|
6582
|
+
if (this._select)
|
|
6583
|
+
this.id = this._select._registerOption();
|
|
6584
|
+
}
|
|
6585
|
+
/**
|
|
6586
|
+
* @description
|
|
6587
|
+
* Tracks the value bound to the option element. Unlike the value binding,
|
|
6588
|
+
* ngValue supports binding to objects.
|
|
6589
|
+
*/
|
|
6590
|
+
set ngValue(value) {
|
|
6591
|
+
if (this._select == null)
|
|
6592
|
+
return;
|
|
6593
|
+
this._select._optionMap.set(this.id, value);
|
|
6594
|
+
this._setElementValue(_buildValueString$1(this.id, value));
|
|
6595
|
+
this._select._writeValueAfterRender();
|
|
6596
|
+
}
|
|
6597
|
+
/**
|
|
6598
|
+
* @description
|
|
6599
|
+
* Tracks simple string values bound to the option element.
|
|
6600
|
+
* For objects, use the `ngValue` input binding.
|
|
6601
|
+
*/
|
|
6602
|
+
set value(value) {
|
|
6603
|
+
this._setElementValue(value);
|
|
6604
|
+
if (this._select)
|
|
6605
|
+
this._select._writeValueAfterRender();
|
|
6606
|
+
}
|
|
6566
6607
|
/** @internal */
|
|
6567
|
-
|
|
6608
|
+
_setElementValue(value) {
|
|
6609
|
+
this._renderer.setProperty(this._element.nativeElement, 'value', value);
|
|
6610
|
+
}
|
|
6568
6611
|
/** @docs-private */
|
|
6569
|
-
|
|
6570
|
-
|
|
6612
|
+
ngOnDestroy() {
|
|
6613
|
+
if (this._select) {
|
|
6614
|
+
this._select._optionMap.delete(this.id);
|
|
6615
|
+
this._select._writeValueAfterRender();
|
|
6616
|
+
}
|
|
6571
6617
|
}
|
|
6572
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
6573
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type:
|
|
6618
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: NgSelectOption, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: SelectControlValueAccessor, host: true, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
6619
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: NgSelectOption, isStandalone: false, selector: "option", inputs: { ngValue: "ngValue", value: "value" }, ngImport: i0 });
|
|
6574
6620
|
}
|
|
6575
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
6621
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: NgSelectOption, decorators: [{
|
|
6576
6622
|
type: Directive,
|
|
6577
6623
|
args: [{
|
|
6578
|
-
selector: '
|
|
6579
|
-
providers: [REQUIRED_VALIDATOR],
|
|
6580
|
-
host: { '[attr.required]': '_enabled ? "" : null' },
|
|
6624
|
+
selector: 'option',
|
|
6581
6625
|
standalone: false,
|
|
6582
6626
|
}]
|
|
6583
|
-
}],
|
|
6584
|
-
|
|
6627
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: SelectControlValueAccessor, decorators: [{
|
|
6628
|
+
type: Optional
|
|
6629
|
+
}, {
|
|
6630
|
+
type: Host
|
|
6631
|
+
}] }], propDecorators: { ngValue: [{
|
|
6632
|
+
type: Input,
|
|
6633
|
+
args: ['ngValue']
|
|
6634
|
+
}], value: [{
|
|
6635
|
+
type: Input,
|
|
6636
|
+
args: ['value']
|
|
6585
6637
|
}] } });
|
|
6638
|
+
|
|
6639
|
+
const SELECT_MULTIPLE_VALUE_ACCESSOR = {
|
|
6640
|
+
provide: NG_VALUE_ACCESSOR,
|
|
6641
|
+
useExisting: forwardRef(() => SelectMultipleControlValueAccessor),
|
|
6642
|
+
multi: true,
|
|
6643
|
+
};
|
|
6644
|
+
function _buildValueString(id, value) {
|
|
6645
|
+
if (id == null)
|
|
6646
|
+
return `${value}`;
|
|
6647
|
+
if (typeof value === 'string')
|
|
6648
|
+
value = `'${value}'`;
|
|
6649
|
+
if (value && typeof value === 'object')
|
|
6650
|
+
value = 'Object';
|
|
6651
|
+
return `${id}: ${value}`.slice(0, 50);
|
|
6652
|
+
}
|
|
6653
|
+
function _extractId(valueString) {
|
|
6654
|
+
return valueString.split(':')[0];
|
|
6655
|
+
}
|
|
6586
6656
|
/**
|
|
6587
|
-
*
|
|
6588
|
-
* `
|
|
6657
|
+
* @description
|
|
6658
|
+
* The `ControlValueAccessor` for writing multi-select control values and listening to multi-select
|
|
6659
|
+
* control changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and
|
|
6660
|
+
* `NgModel` directives.
|
|
6589
6661
|
*
|
|
6590
|
-
* @see
|
|
6662
|
+
* @see {@link SelectControlValueAccessor}
|
|
6591
6663
|
*
|
|
6592
6664
|
* @usageNotes
|
|
6593
6665
|
*
|
|
6594
|
-
* ###
|
|
6666
|
+
* ### Using a multi-select control
|
|
6595
6667
|
*
|
|
6596
|
-
* The
|
|
6597
|
-
*
|
|
6668
|
+
* The follow example shows you how to use a multi-select control with a reactive form.
|
|
6669
|
+
*
|
|
6670
|
+
* ```ts
|
|
6671
|
+
* const countryControl = new FormControl();
|
|
6672
|
+
* ```
|
|
6598
6673
|
*
|
|
6599
6674
|
* ```html
|
|
6600
|
-
* <
|
|
6675
|
+
* <select multiple name="countries" [formControl]="countryControl">
|
|
6676
|
+
* @for(country of countries; track $index) {
|
|
6677
|
+
* <option [ngValue]="country">{{ country.name }}</option>
|
|
6678
|
+
* }
|
|
6679
|
+
* </select>
|
|
6601
6680
|
* ```
|
|
6602
6681
|
*
|
|
6603
|
-
*
|
|
6604
|
-
* @ngModule FormsModule
|
|
6605
|
-
* @ngModule ReactiveFormsModule
|
|
6606
|
-
*/
|
|
6607
|
-
class CheckboxRequiredValidator extends RequiredValidator {
|
|
6608
|
-
/** @internal */
|
|
6609
|
-
createValidator = (input) => requiredTrueValidator;
|
|
6610
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CheckboxRequiredValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
6611
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: CheckboxRequiredValidator, isStandalone: false, selector: "input[type=checkbox][required][formControlName],input[type=checkbox][required][formControl],input[type=checkbox][required][ngModel]", host: { properties: { "attr.required": "_enabled ? \"\" : null" } }, providers: [CHECKBOX_REQUIRED_VALIDATOR], usesInheritance: true, ngImport: i0 });
|
|
6612
|
-
}
|
|
6613
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CheckboxRequiredValidator, decorators: [{
|
|
6614
|
-
type: Directive,
|
|
6615
|
-
args: [{
|
|
6616
|
-
selector: 'input[type=checkbox][required][formControlName],input[type=checkbox][required][formControl],input[type=checkbox][required][ngModel]',
|
|
6617
|
-
providers: [CHECKBOX_REQUIRED_VALIDATOR],
|
|
6618
|
-
host: { '[attr.required]': '_enabled ? "" : null' },
|
|
6619
|
-
standalone: false,
|
|
6620
|
-
}]
|
|
6621
|
-
}] });
|
|
6622
|
-
/**
|
|
6623
|
-
* @description
|
|
6624
|
-
* Provider which adds `EmailValidator` to the `NG_VALIDATORS` multi-provider list.
|
|
6625
|
-
*/
|
|
6626
|
-
const EMAIL_VALIDATOR = {
|
|
6627
|
-
provide: NG_VALIDATORS,
|
|
6628
|
-
useExisting: forwardRef(() => EmailValidator),
|
|
6629
|
-
multi: true,
|
|
6630
|
-
};
|
|
6631
|
-
/**
|
|
6632
|
-
* A directive that adds the `email` validator to controls marked with the
|
|
6633
|
-
* `email` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
|
6634
|
-
*
|
|
6635
|
-
* The email validation is based on the WHATWG HTML specification with some enhancements to
|
|
6636
|
-
* incorporate more RFC rules. More information can be found on the [Validators.email
|
|
6637
|
-
* page](api/forms/Validators#email).
|
|
6638
|
-
*
|
|
6639
|
-
* @see [Form Validation](guide/forms/form-validation)
|
|
6640
|
-
*
|
|
6641
|
-
* @usageNotes
|
|
6642
|
-
*
|
|
6643
|
-
* ### Adding an email validator
|
|
6644
|
-
*
|
|
6645
|
-
* The following example shows how to add an email validator to an input attached to an ngModel
|
|
6646
|
-
* binding.
|
|
6682
|
+
* ### Customizing option selection
|
|
6647
6683
|
*
|
|
6648
|
-
*
|
|
6649
|
-
*
|
|
6650
|
-
* <input type="email" name="email" ngModel email="true">
|
|
6651
|
-
* <input type="email" name="email" ngModel [email]="true">
|
|
6652
|
-
* ```
|
|
6684
|
+
* To customize the default option comparison algorithm, `<select>` supports `compareWith` input.
|
|
6685
|
+
* See the `SelectControlValueAccessor` for usage.
|
|
6653
6686
|
*
|
|
6654
|
-
* @publicApi
|
|
6655
|
-
* @ngModule FormsModule
|
|
6656
6687
|
* @ngModule ReactiveFormsModule
|
|
6688
|
+
* @ngModule FormsModule
|
|
6689
|
+
* @publicApi
|
|
6657
6690
|
*/
|
|
6658
|
-
class
|
|
6691
|
+
class SelectMultipleControlValueAccessor extends BuiltInControlValueAccessor {
|
|
6692
|
+
/**
|
|
6693
|
+
* The current value.
|
|
6694
|
+
* @docs-private
|
|
6695
|
+
*/
|
|
6696
|
+
value;
|
|
6697
|
+
/** @internal */
|
|
6698
|
+
_optionMap = new Map();
|
|
6699
|
+
/** @internal */
|
|
6700
|
+
_idCounter = 0;
|
|
6659
6701
|
/**
|
|
6660
6702
|
* @description
|
|
6661
|
-
* Tracks
|
|
6703
|
+
* Tracks the option comparison algorithm for tracking identities when
|
|
6704
|
+
* checking for changes.
|
|
6662
6705
|
*/
|
|
6663
|
-
|
|
6706
|
+
set compareWith(fn) {
|
|
6707
|
+
if (typeof fn !== 'function' && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
6708
|
+
throw new _RuntimeError(1201 /* RuntimeErrorCode.COMPAREWITH_NOT_A_FN */, `compareWith must be a function, but received ${JSON.stringify(fn)}`);
|
|
6709
|
+
}
|
|
6710
|
+
this._compareWith = fn;
|
|
6711
|
+
}
|
|
6712
|
+
_compareWith = Object.is;
|
|
6713
|
+
/**
|
|
6714
|
+
* Sets the "value" property on one or of more of the select's options.
|
|
6715
|
+
* @docs-private
|
|
6716
|
+
*/
|
|
6717
|
+
writeValue(value) {
|
|
6718
|
+
this.value = value;
|
|
6719
|
+
let optionSelectedStateSetter;
|
|
6720
|
+
if (Array.isArray(value)) {
|
|
6721
|
+
// convert values to ids
|
|
6722
|
+
const ids = value.map((v) => this._getOptionId(v));
|
|
6723
|
+
optionSelectedStateSetter = (opt, o) => {
|
|
6724
|
+
opt._setSelected(ids.indexOf(o.toString()) > -1);
|
|
6725
|
+
};
|
|
6726
|
+
}
|
|
6727
|
+
else {
|
|
6728
|
+
optionSelectedStateSetter = (opt, o) => {
|
|
6729
|
+
opt._setSelected(false);
|
|
6730
|
+
};
|
|
6731
|
+
}
|
|
6732
|
+
this._optionMap.forEach(optionSelectedStateSetter);
|
|
6733
|
+
}
|
|
6734
|
+
/**
|
|
6735
|
+
* Registers a function called when the control value changes
|
|
6736
|
+
* and writes an array of the selected options.
|
|
6737
|
+
* @docs-private
|
|
6738
|
+
*/
|
|
6739
|
+
registerOnChange(fn) {
|
|
6740
|
+
this.onChange = (element) => {
|
|
6741
|
+
const selected = [];
|
|
6742
|
+
const selectedOptions = element.selectedOptions;
|
|
6743
|
+
if (selectedOptions !== undefined) {
|
|
6744
|
+
const options = selectedOptions;
|
|
6745
|
+
for (let i = 0; i < options.length; i++) {
|
|
6746
|
+
const opt = options[i];
|
|
6747
|
+
const val = this._getOptionValue(opt.value);
|
|
6748
|
+
selected.push(val);
|
|
6749
|
+
}
|
|
6750
|
+
}
|
|
6751
|
+
// Degrade to use `options` when `selectedOptions` property is not available.
|
|
6752
|
+
// Note: the `selectedOptions` is available in all supported browsers, but the Domino lib
|
|
6753
|
+
// doesn't have it currently, see https://github.com/fgnass/domino/issues/177.
|
|
6754
|
+
else {
|
|
6755
|
+
const options = element.options;
|
|
6756
|
+
for (let i = 0; i < options.length; i++) {
|
|
6757
|
+
const opt = options[i];
|
|
6758
|
+
if (opt.selected) {
|
|
6759
|
+
const val = this._getOptionValue(opt.value);
|
|
6760
|
+
selected.push(val);
|
|
6761
|
+
}
|
|
6762
|
+
}
|
|
6763
|
+
}
|
|
6764
|
+
this.value = selected;
|
|
6765
|
+
fn(selected);
|
|
6766
|
+
};
|
|
6767
|
+
}
|
|
6664
6768
|
/** @internal */
|
|
6665
|
-
|
|
6769
|
+
_registerOption(value) {
|
|
6770
|
+
const id = (this._idCounter++).toString();
|
|
6771
|
+
this._optionMap.set(id, value);
|
|
6772
|
+
return id;
|
|
6773
|
+
}
|
|
6666
6774
|
/** @internal */
|
|
6667
|
-
|
|
6775
|
+
_getOptionId(value) {
|
|
6776
|
+
for (const id of this._optionMap.keys()) {
|
|
6777
|
+
if (this._compareWith(this._optionMap.get(id)._value, value))
|
|
6778
|
+
return id;
|
|
6779
|
+
}
|
|
6780
|
+
return null;
|
|
6781
|
+
}
|
|
6668
6782
|
/** @internal */
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
return input;
|
|
6783
|
+
_getOptionValue(valueString) {
|
|
6784
|
+
const id = _extractId(valueString);
|
|
6785
|
+
return this._optionMap.has(id) ? this._optionMap.get(id)._value : valueString;
|
|
6673
6786
|
}
|
|
6674
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
6675
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type:
|
|
6787
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: SelectMultipleControlValueAccessor, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
6788
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: SelectMultipleControlValueAccessor, isStandalone: false, selector: "select[multiple][formControlName],select[multiple][formControl],select[multiple][ngModel]", inputs: { compareWith: "compareWith" }, host: { listeners: { "change": "onChange($event.target)", "blur": "onTouched()" } }, providers: [SELECT_MULTIPLE_VALUE_ACCESSOR], usesInheritance: true, ngImport: i0 });
|
|
6676
6789
|
}
|
|
6677
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
6790
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: SelectMultipleControlValueAccessor, decorators: [{
|
|
6678
6791
|
type: Directive,
|
|
6679
6792
|
args: [{
|
|
6680
|
-
selector: '[
|
|
6681
|
-
|
|
6793
|
+
selector: 'select[multiple][formControlName],select[multiple][formControl],select[multiple][ngModel]',
|
|
6794
|
+
host: { '(change)': 'onChange($event.target)', '(blur)': 'onTouched()' },
|
|
6795
|
+
providers: [SELECT_MULTIPLE_VALUE_ACCESSOR],
|
|
6682
6796
|
standalone: false,
|
|
6683
6797
|
}]
|
|
6684
|
-
}], propDecorators: {
|
|
6798
|
+
}], propDecorators: { compareWith: [{
|
|
6685
6799
|
type: Input
|
|
6686
6800
|
}] } });
|
|
6687
6801
|
/**
|
|
6688
6802
|
* @description
|
|
6689
|
-
*
|
|
6690
|
-
*/
|
|
6691
|
-
const MIN_LENGTH_VALIDATOR = {
|
|
6692
|
-
provide: NG_VALIDATORS,
|
|
6693
|
-
useExisting: forwardRef(() => MinLengthValidator),
|
|
6694
|
-
multi: true,
|
|
6695
|
-
};
|
|
6696
|
-
/**
|
|
6697
|
-
* A directive that adds minimum length validation to controls marked with the
|
|
6698
|
-
* `minlength` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
|
6699
|
-
*
|
|
6700
|
-
* @see [Form Validation](guide/forms/form-validation)
|
|
6701
|
-
*
|
|
6702
|
-
* @usageNotes
|
|
6703
|
-
*
|
|
6704
|
-
* ### Adding a minimum length validator
|
|
6705
|
-
*
|
|
6706
|
-
* The following example shows how to add a minimum length validator to an input attached to an
|
|
6707
|
-
* ngModel binding.
|
|
6803
|
+
* Marks `<option>` as dynamic, so Angular can be notified when options change.
|
|
6708
6804
|
*
|
|
6709
|
-
*
|
|
6710
|
-
* <input name="firstName" ngModel minlength="4">
|
|
6711
|
-
* ```
|
|
6805
|
+
* @see {@link SelectMultipleControlValueAccessor}
|
|
6712
6806
|
*
|
|
6713
6807
|
* @ngModule ReactiveFormsModule
|
|
6714
6808
|
* @ngModule FormsModule
|
|
6715
6809
|
* @publicApi
|
|
6716
6810
|
*/
|
|
6717
|
-
class
|
|
6811
|
+
class ɵNgSelectMultipleOption {
|
|
6812
|
+
_element;
|
|
6813
|
+
_renderer;
|
|
6814
|
+
_select;
|
|
6815
|
+
id;
|
|
6816
|
+
/** @internal */
|
|
6817
|
+
_value;
|
|
6818
|
+
constructor(_element, _renderer, _select) {
|
|
6819
|
+
this._element = _element;
|
|
6820
|
+
this._renderer = _renderer;
|
|
6821
|
+
this._select = _select;
|
|
6822
|
+
if (this._select) {
|
|
6823
|
+
this.id = this._select._registerOption(this);
|
|
6824
|
+
}
|
|
6825
|
+
}
|
|
6718
6826
|
/**
|
|
6719
6827
|
* @description
|
|
6720
|
-
* Tracks
|
|
6828
|
+
* Tracks the value bound to the option element. Unlike the value binding,
|
|
6829
|
+
* ngValue supports binding to objects.
|
|
6721
6830
|
*/
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6831
|
+
set ngValue(value) {
|
|
6832
|
+
if (this._select == null)
|
|
6833
|
+
return;
|
|
6834
|
+
this._value = value;
|
|
6835
|
+
this._setElementValue(_buildValueString(this.id, value));
|
|
6836
|
+
this._select.writeValue(this._select.value);
|
|
6837
|
+
}
|
|
6838
|
+
/**
|
|
6839
|
+
* @description
|
|
6840
|
+
* Tracks simple string values bound to the option element.
|
|
6841
|
+
* For objects, use the `ngValue` input binding.
|
|
6842
|
+
*/
|
|
6843
|
+
set value(value) {
|
|
6844
|
+
if (this._select) {
|
|
6845
|
+
this._value = value;
|
|
6846
|
+
this._setElementValue(_buildValueString(this.id, value));
|
|
6847
|
+
this._select.writeValue(this._select.value);
|
|
6848
|
+
}
|
|
6849
|
+
else {
|
|
6850
|
+
this._setElementValue(value);
|
|
6851
|
+
}
|
|
6852
|
+
}
|
|
6725
6853
|
/** @internal */
|
|
6726
|
-
|
|
6854
|
+
_setElementValue(value) {
|
|
6855
|
+
this._renderer.setProperty(this._element.nativeElement, 'value', value);
|
|
6856
|
+
}
|
|
6727
6857
|
/** @internal */
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6858
|
+
_setSelected(selected) {
|
|
6859
|
+
this._renderer.setProperty(this._element.nativeElement, 'selected', selected);
|
|
6860
|
+
}
|
|
6861
|
+
/** @docs-private */
|
|
6862
|
+
ngOnDestroy() {
|
|
6863
|
+
if (this._select) {
|
|
6864
|
+
this._select._optionMap.delete(this.id);
|
|
6865
|
+
this._select.writeValue(this._select.value);
|
|
6866
|
+
}
|
|
6867
|
+
}
|
|
6868
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ɵNgSelectMultipleOption, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: SelectMultipleControlValueAccessor, host: true, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
6869
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: ɵNgSelectMultipleOption, isStandalone: false, selector: "option", inputs: { ngValue: "ngValue", value: "value" }, ngImport: i0 });
|
|
6731
6870
|
}
|
|
6732
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
6871
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ɵNgSelectMultipleOption, decorators: [{
|
|
6733
6872
|
type: Directive,
|
|
6734
6873
|
args: [{
|
|
6735
|
-
selector: '
|
|
6736
|
-
providers: [MIN_LENGTH_VALIDATOR],
|
|
6737
|
-
host: { '[attr.minlength]': '_enabled ? minlength : null' },
|
|
6874
|
+
selector: 'option',
|
|
6738
6875
|
standalone: false,
|
|
6739
6876
|
}]
|
|
6740
|
-
}],
|
|
6741
|
-
|
|
6877
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: SelectMultipleControlValueAccessor, decorators: [{
|
|
6878
|
+
type: Optional
|
|
6879
|
+
}, {
|
|
6880
|
+
type: Host
|
|
6881
|
+
}] }], propDecorators: { ngValue: [{
|
|
6882
|
+
type: Input,
|
|
6883
|
+
args: ['ngValue']
|
|
6884
|
+
}], value: [{
|
|
6885
|
+
type: Input,
|
|
6886
|
+
args: ['value']
|
|
6742
6887
|
}] } });
|
|
6888
|
+
|
|
6889
|
+
/**
|
|
6890
|
+
* Method that updates string to integer if not already a number
|
|
6891
|
+
*
|
|
6892
|
+
* @param value The value to convert to integer.
|
|
6893
|
+
* @returns value of parameter converted to number or integer.
|
|
6894
|
+
*/
|
|
6895
|
+
function toInteger(value) {
|
|
6896
|
+
return typeof value === 'number' ? value : parseInt(value, 10);
|
|
6897
|
+
}
|
|
6898
|
+
/**
|
|
6899
|
+
* Method that ensures that provided value is a float (and converts it to float if needed).
|
|
6900
|
+
*
|
|
6901
|
+
* @param value The value to convert to float.
|
|
6902
|
+
* @returns value of parameter converted to number or float.
|
|
6903
|
+
*/
|
|
6904
|
+
function toFloat(value) {
|
|
6905
|
+
return typeof value === 'number' ? value : parseFloat(value);
|
|
6906
|
+
}
|
|
6907
|
+
/**
|
|
6908
|
+
* A base class for Validator-based Directives. The class contains common logic shared across such
|
|
6909
|
+
* Directives.
|
|
6910
|
+
*
|
|
6911
|
+
* For internal use only, this class is not intended for use outside of the Forms package.
|
|
6912
|
+
*/
|
|
6913
|
+
class AbstractValidatorDirective {
|
|
6914
|
+
_validator = nullValidator;
|
|
6915
|
+
_onChange;
|
|
6916
|
+
/**
|
|
6917
|
+
* A flag that tracks whether this validator is enabled.
|
|
6918
|
+
*
|
|
6919
|
+
* Marking it `internal` (vs `protected`), so that this flag can be used in host bindings of
|
|
6920
|
+
* directive classes that extend this base class.
|
|
6921
|
+
* @internal
|
|
6922
|
+
*/
|
|
6923
|
+
_enabled;
|
|
6924
|
+
/** @docs-private */
|
|
6925
|
+
ngOnChanges(changes) {
|
|
6926
|
+
if (this.inputName in changes) {
|
|
6927
|
+
const input = this.normalizeInput(changes[this.inputName].currentValue);
|
|
6928
|
+
this._enabled = this.enabled(input);
|
|
6929
|
+
this._validator = this._enabled ? this.createValidator(input) : nullValidator;
|
|
6930
|
+
if (this._onChange) {
|
|
6931
|
+
this._onChange();
|
|
6932
|
+
}
|
|
6933
|
+
}
|
|
6934
|
+
}
|
|
6935
|
+
/** @docs-private */
|
|
6936
|
+
validate(control) {
|
|
6937
|
+
return this._validator(control);
|
|
6938
|
+
}
|
|
6939
|
+
/** @docs-private */
|
|
6940
|
+
registerOnValidatorChange(fn) {
|
|
6941
|
+
this._onChange = fn;
|
|
6942
|
+
}
|
|
6943
|
+
/**
|
|
6944
|
+
* @description
|
|
6945
|
+
* Determines whether this validator should be active or not based on an input.
|
|
6946
|
+
* Base class implementation checks whether an input is defined (if the value is different from
|
|
6947
|
+
* `null` and `undefined`). Validator classes that extend this base class can override this
|
|
6948
|
+
* function with the logic specific to a particular validator directive.
|
|
6949
|
+
*/
|
|
6950
|
+
enabled(input) {
|
|
6951
|
+
return input != null /* both `null` and `undefined` */;
|
|
6952
|
+
}
|
|
6953
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: AbstractValidatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
6954
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: AbstractValidatorDirective, isStandalone: true, usesOnChanges: true, ngImport: i0 });
|
|
6955
|
+
}
|
|
6956
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: AbstractValidatorDirective, decorators: [{
|
|
6957
|
+
type: Directive
|
|
6958
|
+
}] });
|
|
6743
6959
|
/**
|
|
6744
6960
|
* @description
|
|
6745
|
-
* Provider which adds `
|
|
6961
|
+
* Provider which adds `MaxValidator` to the `NG_VALIDATORS` multi-provider list.
|
|
6746
6962
|
*/
|
|
6747
|
-
const
|
|
6963
|
+
const MAX_VALIDATOR = {
|
|
6748
6964
|
provide: NG_VALIDATORS,
|
|
6749
|
-
useExisting: forwardRef(() =>
|
|
6965
|
+
useExisting: forwardRef(() => MaxValidator),
|
|
6750
6966
|
multi: true,
|
|
6751
6967
|
};
|
|
6752
6968
|
/**
|
|
6753
|
-
* A directive
|
|
6754
|
-
* `
|
|
6969
|
+
* A directive which installs the {@link MaxValidator} for any `formControlName`,
|
|
6970
|
+
* `formControl`, or control with `ngModel` that also has a `max` attribute.
|
|
6755
6971
|
*
|
|
6756
6972
|
* @see [Form Validation](guide/forms/form-validation)
|
|
6757
6973
|
*
|
|
6758
6974
|
* @usageNotes
|
|
6759
6975
|
*
|
|
6760
|
-
* ### Adding a
|
|
6976
|
+
* ### Adding a max validator
|
|
6761
6977
|
*
|
|
6762
|
-
* The following example shows how to add a
|
|
6978
|
+
* The following example shows how to add a max validator to an input attached to an
|
|
6763
6979
|
* ngModel binding.
|
|
6764
6980
|
*
|
|
6765
6981
|
* ```html
|
|
6766
|
-
* <input
|
|
6982
|
+
* <input type="number" ngModel max="4">
|
|
6767
6983
|
* ```
|
|
6768
6984
|
*
|
|
6769
6985
|
* @ngModule ReactiveFormsModule
|
|
6770
6986
|
* @ngModule FormsModule
|
|
6771
6987
|
* @publicApi
|
|
6772
6988
|
*/
|
|
6773
|
-
class
|
|
6989
|
+
class MaxValidator extends AbstractValidatorDirective {
|
|
6774
6990
|
/**
|
|
6775
6991
|
* @description
|
|
6776
|
-
* Tracks changes to the
|
|
6992
|
+
* Tracks changes to the max bound to this directive.
|
|
6777
6993
|
*/
|
|
6778
|
-
|
|
6994
|
+
max;
|
|
6779
6995
|
/** @internal */
|
|
6780
|
-
inputName = '
|
|
6996
|
+
inputName = 'max';
|
|
6781
6997
|
/** @internal */
|
|
6782
|
-
normalizeInput = (input) =>
|
|
6998
|
+
normalizeInput = (input) => toFloat(input);
|
|
6783
6999
|
/** @internal */
|
|
6784
|
-
createValidator = (
|
|
6785
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
6786
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type:
|
|
7000
|
+
createValidator = (max) => maxValidator(max);
|
|
7001
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MaxValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
7002
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: MaxValidator, isStandalone: false, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: { max: "max" }, host: { properties: { "attr.max": "_enabled ? max : null" } }, providers: [MAX_VALIDATOR], usesInheritance: true, ngImport: i0 });
|
|
6787
7003
|
}
|
|
6788
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
7004
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MaxValidator, decorators: [{
|
|
6789
7005
|
type: Directive,
|
|
6790
7006
|
args: [{
|
|
6791
|
-
selector: '[
|
|
6792
|
-
providers: [
|
|
6793
|
-
host: { '[attr.
|
|
7007
|
+
selector: 'input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]',
|
|
7008
|
+
providers: [MAX_VALIDATOR],
|
|
7009
|
+
host: { '[attr.max]': '_enabled ? max : null' },
|
|
6794
7010
|
standalone: false,
|
|
6795
7011
|
}]
|
|
6796
|
-
}], propDecorators: {
|
|
7012
|
+
}], propDecorators: { max: [{
|
|
6797
7013
|
type: Input
|
|
6798
7014
|
}] } });
|
|
6799
7015
|
/**
|
|
6800
7016
|
* @description
|
|
6801
|
-
* Provider which adds `
|
|
7017
|
+
* Provider which adds `MinValidator` to the `NG_VALIDATORS` multi-provider list.
|
|
6802
7018
|
*/
|
|
6803
|
-
const
|
|
7019
|
+
const MIN_VALIDATOR = {
|
|
6804
7020
|
provide: NG_VALIDATORS,
|
|
6805
|
-
useExisting: forwardRef(() =>
|
|
7021
|
+
useExisting: forwardRef(() => MinValidator),
|
|
6806
7022
|
multi: true,
|
|
6807
7023
|
};
|
|
6808
7024
|
/**
|
|
6809
|
-
* @
|
|
6810
|
-
*
|
|
6811
|
-
* `pattern` attribute. The regex must match the entire control value.
|
|
6812
|
-
* The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
|
7025
|
+
* A directive which installs the {@link MinValidator} for any `formControlName`,
|
|
7026
|
+
* `formControl`, or control with `ngModel` that also has a `min` attribute.
|
|
6813
7027
|
*
|
|
6814
7028
|
* @see [Form Validation](guide/forms/form-validation)
|
|
6815
7029
|
*
|
|
6816
7030
|
* @usageNotes
|
|
6817
7031
|
*
|
|
6818
|
-
* ### Adding a
|
|
7032
|
+
* ### Adding a min validator
|
|
6819
7033
|
*
|
|
6820
|
-
* The following example shows how to add a
|
|
7034
|
+
* The following example shows how to add a min validator to an input attached to an
|
|
6821
7035
|
* ngModel binding.
|
|
6822
7036
|
*
|
|
6823
7037
|
* ```html
|
|
6824
|
-
* <input
|
|
7038
|
+
* <input type="number" ngModel min="4">
|
|
6825
7039
|
* ```
|
|
6826
7040
|
*
|
|
6827
7041
|
* @ngModule ReactiveFormsModule
|
|
6828
7042
|
* @ngModule FormsModule
|
|
6829
7043
|
* @publicApi
|
|
6830
7044
|
*/
|
|
6831
|
-
class
|
|
7045
|
+
class MinValidator extends AbstractValidatorDirective {
|
|
6832
7046
|
/**
|
|
6833
7047
|
* @description
|
|
6834
|
-
* Tracks changes to the
|
|
7048
|
+
* Tracks changes to the min bound to this directive.
|
|
6835
7049
|
*/
|
|
6836
|
-
|
|
7050
|
+
min;
|
|
6837
7051
|
/** @internal */
|
|
6838
|
-
inputName = '
|
|
7052
|
+
inputName = 'min';
|
|
6839
7053
|
/** @internal */
|
|
6840
|
-
normalizeInput = (input) => input;
|
|
7054
|
+
normalizeInput = (input) => toFloat(input);
|
|
6841
7055
|
/** @internal */
|
|
6842
|
-
createValidator = (
|
|
6843
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
6844
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type:
|
|
7056
|
+
createValidator = (min) => minValidator(min);
|
|
7057
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MinValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
7058
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: MinValidator, isStandalone: false, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: { min: "min" }, host: { properties: { "attr.min": "_enabled ? min : null" } }, providers: [MIN_VALIDATOR], usesInheritance: true, ngImport: i0 });
|
|
6845
7059
|
}
|
|
6846
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type:
|
|
7060
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MinValidator, decorators: [{
|
|
6847
7061
|
type: Directive,
|
|
6848
7062
|
args: [{
|
|
6849
|
-
selector: '[
|
|
6850
|
-
providers: [
|
|
6851
|
-
host: { '[attr.
|
|
7063
|
+
selector: 'input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]',
|
|
7064
|
+
providers: [MIN_VALIDATOR],
|
|
7065
|
+
host: { '[attr.min]': '_enabled ? min : null' },
|
|
6852
7066
|
standalone: false,
|
|
6853
7067
|
}]
|
|
6854
|
-
}], propDecorators: {
|
|
7068
|
+
}], propDecorators: { min: [{
|
|
6855
7069
|
type: Input
|
|
6856
7070
|
}] } });
|
|
6857
|
-
|
|
6858
|
-
const SHARED_FORM_DIRECTIVES = [
|
|
6859
|
-
ɵNgNoValidate,
|
|
6860
|
-
NgSelectOption,
|
|
6861
|
-
ɵNgSelectMultipleOption,
|
|
6862
|
-
DefaultValueAccessor,
|
|
6863
|
-
NumberValueAccessor,
|
|
6864
|
-
RangeValueAccessor,
|
|
6865
|
-
CheckboxControlValueAccessor,
|
|
6866
|
-
SelectControlValueAccessor,
|
|
6867
|
-
SelectMultipleControlValueAccessor,
|
|
6868
|
-
RadioControlValueAccessor,
|
|
6869
|
-
NgControlStatus,
|
|
6870
|
-
NgControlStatusGroup,
|
|
6871
|
-
RequiredValidator,
|
|
6872
|
-
MinLengthValidator,
|
|
6873
|
-
MaxLengthValidator,
|
|
6874
|
-
PatternValidator,
|
|
6875
|
-
CheckboxRequiredValidator,
|
|
6876
|
-
EmailValidator,
|
|
6877
|
-
MinValidator,
|
|
6878
|
-
MaxValidator,
|
|
6879
|
-
];
|
|
6880
|
-
const TEMPLATE_DRIVEN_DIRECTIVES = [NgModel, NgModelGroup, NgForm];
|
|
6881
|
-
const REACTIVE_DRIVEN_DIRECTIVES = [
|
|
6882
|
-
FormControlDirective,
|
|
6883
|
-
FormGroupDirective,
|
|
6884
|
-
FormControlName,
|
|
6885
|
-
FormGroupName,
|
|
6886
|
-
FormArrayName,
|
|
6887
|
-
];
|
|
6888
7071
|
/**
|
|
6889
|
-
*
|
|
7072
|
+
* @description
|
|
7073
|
+
* Provider which adds `RequiredValidator` to the `NG_VALIDATORS` multi-provider list.
|
|
6890
7074
|
*/
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
CheckboxRequiredValidator,
|
|
6910
|
-
EmailValidator,
|
|
6911
|
-
MinValidator,
|
|
6912
|
-
MaxValidator], exports: [ɵNgNoValidate,
|
|
6913
|
-
NgSelectOption,
|
|
6914
|
-
ɵNgSelectMultipleOption,
|
|
6915
|
-
DefaultValueAccessor,
|
|
6916
|
-
NumberValueAccessor,
|
|
6917
|
-
RangeValueAccessor,
|
|
6918
|
-
CheckboxControlValueAccessor,
|
|
6919
|
-
SelectControlValueAccessor,
|
|
6920
|
-
SelectMultipleControlValueAccessor,
|
|
6921
|
-
RadioControlValueAccessor,
|
|
6922
|
-
NgControlStatus,
|
|
6923
|
-
NgControlStatusGroup,
|
|
6924
|
-
RequiredValidator,
|
|
6925
|
-
MinLengthValidator,
|
|
6926
|
-
MaxLengthValidator,
|
|
6927
|
-
PatternValidator,
|
|
6928
|
-
CheckboxRequiredValidator,
|
|
6929
|
-
EmailValidator,
|
|
6930
|
-
MinValidator,
|
|
6931
|
-
MaxValidator] });
|
|
6932
|
-
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ɵInternalFormsSharedModule });
|
|
6933
|
-
}
|
|
6934
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ɵInternalFormsSharedModule, decorators: [{
|
|
6935
|
-
type: NgModule,
|
|
6936
|
-
args: [{
|
|
6937
|
-
declarations: SHARED_FORM_DIRECTIVES,
|
|
6938
|
-
exports: SHARED_FORM_DIRECTIVES,
|
|
6939
|
-
}]
|
|
6940
|
-
}] });
|
|
6941
|
-
|
|
6942
|
-
/**
|
|
6943
|
-
* Tracks the value and validity state of an array of `FormControl`,
|
|
6944
|
-
* `FormGroup` or `FormArray` instances.
|
|
7075
|
+
const REQUIRED_VALIDATOR = {
|
|
7076
|
+
provide: NG_VALIDATORS,
|
|
7077
|
+
useExisting: forwardRef(() => RequiredValidator),
|
|
7078
|
+
multi: true,
|
|
7079
|
+
};
|
|
7080
|
+
/**
|
|
7081
|
+
* @description
|
|
7082
|
+
* Provider which adds `CheckboxRequiredValidator` to the `NG_VALIDATORS` multi-provider list.
|
|
7083
|
+
*/
|
|
7084
|
+
const CHECKBOX_REQUIRED_VALIDATOR = {
|
|
7085
|
+
provide: NG_VALIDATORS,
|
|
7086
|
+
useExisting: forwardRef(() => CheckboxRequiredValidator),
|
|
7087
|
+
multi: true,
|
|
7088
|
+
};
|
|
7089
|
+
/**
|
|
7090
|
+
* @description
|
|
7091
|
+
* A directive that adds the `required` validator to any controls marked with the
|
|
7092
|
+
* `required` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
|
6945
7093
|
*
|
|
6946
|
-
*
|
|
6947
|
-
* It calculates its status by reducing the status values of its children. For example, if one of
|
|
6948
|
-
* the controls in a `FormArray` is invalid, the entire array becomes invalid.
|
|
7094
|
+
* @see [Form Validation](guide/forms/form-validation)
|
|
6949
7095
|
*
|
|
6950
|
-
*
|
|
6951
|
-
* If you need a heterogenous array, use {@link UntypedFormArray}.
|
|
7096
|
+
* @usageNotes
|
|
6952
7097
|
*
|
|
6953
|
-
*
|
|
6954
|
-
*
|
|
7098
|
+
* ### Adding a required validator using template-driven forms
|
|
7099
|
+
*
|
|
7100
|
+
* ```html
|
|
7101
|
+
* <input name="fullName" ngModel required>
|
|
7102
|
+
* ```
|
|
7103
|
+
*
|
|
7104
|
+
* @ngModule FormsModule
|
|
7105
|
+
* @ngModule ReactiveFormsModule
|
|
7106
|
+
* @publicApi
|
|
7107
|
+
*/
|
|
7108
|
+
class RequiredValidator extends AbstractValidatorDirective {
|
|
7109
|
+
/**
|
|
7110
|
+
* @description
|
|
7111
|
+
* Tracks changes to the required attribute bound to this directive.
|
|
7112
|
+
*/
|
|
7113
|
+
required;
|
|
7114
|
+
/** @internal */
|
|
7115
|
+
inputName = 'required';
|
|
7116
|
+
/** @internal */
|
|
7117
|
+
normalizeInput = booleanAttribute;
|
|
7118
|
+
/** @internal */
|
|
7119
|
+
createValidator = (input) => requiredValidator;
|
|
7120
|
+
/** @docs-private */
|
|
7121
|
+
enabled(input) {
|
|
7122
|
+
return input;
|
|
7123
|
+
}
|
|
7124
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: RequiredValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
7125
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: RequiredValidator, isStandalone: false, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: { required: "required" }, host: { properties: { "attr.required": "_enabled ? \"\" : null" } }, providers: [REQUIRED_VALIDATOR], usesInheritance: true, ngImport: i0 });
|
|
7126
|
+
}
|
|
7127
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: RequiredValidator, decorators: [{
|
|
7128
|
+
type: Directive,
|
|
7129
|
+
args: [{
|
|
7130
|
+
selector: ':not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]',
|
|
7131
|
+
providers: [REQUIRED_VALIDATOR],
|
|
7132
|
+
host: { '[attr.required]': '_enabled ? "" : null' },
|
|
7133
|
+
standalone: false,
|
|
7134
|
+
}]
|
|
7135
|
+
}], propDecorators: { required: [{
|
|
7136
|
+
type: Input
|
|
7137
|
+
}] } });
|
|
7138
|
+
/**
|
|
7139
|
+
* A Directive that adds the `required` validator to checkbox controls marked with the
|
|
7140
|
+
* `required` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
|
7141
|
+
*
|
|
7142
|
+
* @see [Form Validation](guide/forms/form-validation)
|
|
6955
7143
|
*
|
|
6956
7144
|
* @usageNotes
|
|
6957
7145
|
*
|
|
6958
|
-
* ###
|
|
7146
|
+
* ### Adding a required checkbox validator using template-driven forms
|
|
6959
7147
|
*
|
|
6960
|
-
*
|
|
6961
|
-
*
|
|
6962
|
-
* new FormControl('Nancy', Validators.minLength(2)),
|
|
6963
|
-
* new FormControl('Drew'),
|
|
6964
|
-
* ]);
|
|
7148
|
+
* The following example shows how to add a checkbox required validator to an input attached to an
|
|
7149
|
+
* ngModel binding.
|
|
6965
7150
|
*
|
|
6966
|
-
*
|
|
6967
|
-
*
|
|
7151
|
+
* ```html
|
|
7152
|
+
* <input type="checkbox" name="active" ngModel required>
|
|
6968
7153
|
* ```
|
|
6969
7154
|
*
|
|
6970
|
-
*
|
|
7155
|
+
* @publicApi
|
|
7156
|
+
* @ngModule FormsModule
|
|
7157
|
+
* @ngModule ReactiveFormsModule
|
|
7158
|
+
*/
|
|
7159
|
+
class CheckboxRequiredValidator extends RequiredValidator {
|
|
7160
|
+
/** @internal */
|
|
7161
|
+
createValidator = (input) => requiredTrueValidator;
|
|
7162
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CheckboxRequiredValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
7163
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: CheckboxRequiredValidator, isStandalone: false, selector: "input[type=checkbox][required][formControlName],input[type=checkbox][required][formControl],input[type=checkbox][required][ngModel]", host: { properties: { "attr.required": "_enabled ? \"\" : null" } }, providers: [CHECKBOX_REQUIRED_VALIDATOR], usesInheritance: true, ngImport: i0 });
|
|
7164
|
+
}
|
|
7165
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CheckboxRequiredValidator, decorators: [{
|
|
7166
|
+
type: Directive,
|
|
7167
|
+
args: [{
|
|
7168
|
+
selector: 'input[type=checkbox][required][formControlName],input[type=checkbox][required][formControl],input[type=checkbox][required][ngModel]',
|
|
7169
|
+
providers: [CHECKBOX_REQUIRED_VALIDATOR],
|
|
7170
|
+
host: { '[attr.required]': '_enabled ? "" : null' },
|
|
7171
|
+
standalone: false,
|
|
7172
|
+
}]
|
|
7173
|
+
}] });
|
|
7174
|
+
/**
|
|
7175
|
+
* @description
|
|
7176
|
+
* Provider which adds `EmailValidator` to the `NG_VALIDATORS` multi-provider list.
|
|
7177
|
+
*/
|
|
7178
|
+
const EMAIL_VALIDATOR = {
|
|
7179
|
+
provide: NG_VALIDATORS,
|
|
7180
|
+
useExisting: forwardRef(() => EmailValidator),
|
|
7181
|
+
multi: true,
|
|
7182
|
+
};
|
|
7183
|
+
/**
|
|
7184
|
+
* A directive that adds the `email` validator to controls marked with the
|
|
7185
|
+
* `email` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
|
6971
7186
|
*
|
|
6972
|
-
*
|
|
6973
|
-
*
|
|
6974
|
-
*
|
|
7187
|
+
* The email validation is based on the WHATWG HTML specification with some enhancements to
|
|
7188
|
+
* incorporate more RFC rules. More information can be found on the [Validators.email
|
|
7189
|
+
* page](api/forms/Validators#email).
|
|
6975
7190
|
*
|
|
6976
|
-
*
|
|
6977
|
-
* respectively, or together as part of an options object.
|
|
7191
|
+
* @see [Form Validation](guide/forms/form-validation)
|
|
6978
7192
|
*
|
|
6979
|
-
*
|
|
6980
|
-
* const arr = new FormArray([
|
|
6981
|
-
* new FormControl('Nancy'),
|
|
6982
|
-
* new FormControl('Drew')
|
|
6983
|
-
* ], {validators: myValidator, asyncValidators: myAsyncValidator});
|
|
6984
|
-
* ```
|
|
7193
|
+
* @usageNotes
|
|
6985
7194
|
*
|
|
6986
|
-
* ###
|
|
7195
|
+
* ### Adding an email validator
|
|
6987
7196
|
*
|
|
6988
|
-
* The
|
|
6989
|
-
*
|
|
6990
|
-
* array level, all child controls default to 'blur', unless the child
|
|
6991
|
-
* has explicitly specified a different `updateOn` value.
|
|
7197
|
+
* The following example shows how to add an email validator to an input attached to an ngModel
|
|
7198
|
+
* binding.
|
|
6992
7199
|
*
|
|
6993
|
-
* ```
|
|
6994
|
-
*
|
|
6995
|
-
*
|
|
6996
|
-
*
|
|
7200
|
+
* ```html
|
|
7201
|
+
* <input type="email" name="email" ngModel email>
|
|
7202
|
+
* <input type="email" name="email" ngModel email="true">
|
|
7203
|
+
* <input type="email" name="email" ngModel [email]="true">
|
|
6997
7204
|
* ```
|
|
6998
7205
|
*
|
|
6999
|
-
* ### Adding or removing controls from a form array
|
|
7000
|
-
*
|
|
7001
|
-
* To change the controls in the array, use the `push`, `insert`, `removeAt` or `clear` methods
|
|
7002
|
-
* in `FormArray` itself. These methods ensure the controls are properly tracked in the
|
|
7003
|
-
* form's hierarchy. Do not modify the array of `AbstractControl`s used to instantiate
|
|
7004
|
-
* the `FormArray` directly, as that result in strange and unexpected behavior such
|
|
7005
|
-
* as broken change detection.
|
|
7006
|
-
*
|
|
7007
7206
|
* @publicApi
|
|
7207
|
+
* @ngModule FormsModule
|
|
7208
|
+
* @ngModule ReactiveFormsModule
|
|
7008
7209
|
*/
|
|
7009
|
-
class
|
|
7010
|
-
/**
|
|
7011
|
-
* Creates a new `FormArray` instance.
|
|
7012
|
-
*
|
|
7013
|
-
* @param controls An array of child controls. Each child control is given an index
|
|
7014
|
-
* where it is registered.
|
|
7015
|
-
*
|
|
7016
|
-
* @param validatorOrOpts A synchronous validator function, or an array of
|
|
7017
|
-
* such functions, or an `AbstractControlOptions` object that contains validation functions
|
|
7018
|
-
* and a validation trigger.
|
|
7019
|
-
*
|
|
7020
|
-
* @param asyncValidator A single async validator or array of async validator functions
|
|
7021
|
-
*
|
|
7022
|
-
*/
|
|
7023
|
-
constructor(controls, validatorOrOpts, asyncValidator) {
|
|
7024
|
-
super(pickValidators(validatorOrOpts), pickAsyncValidators(asyncValidator, validatorOrOpts));
|
|
7025
|
-
this.controls = controls;
|
|
7026
|
-
this._initObservables();
|
|
7027
|
-
this._setUpdateStrategy(validatorOrOpts);
|
|
7028
|
-
this._setUpControls();
|
|
7029
|
-
this.updateValueAndValidity({
|
|
7030
|
-
onlySelf: true,
|
|
7031
|
-
// If `asyncValidator` is present, it will trigger control status change from `PENDING` to
|
|
7032
|
-
// `VALID` or `INVALID`.
|
|
7033
|
-
// The status should be broadcasted via the `statusChanges` observable, so we set `emitEvent`
|
|
7034
|
-
// to `true` to allow that during the control creation process.
|
|
7035
|
-
emitEvent: !!this.asyncValidator,
|
|
7036
|
-
});
|
|
7037
|
-
}
|
|
7038
|
-
controls;
|
|
7039
|
-
/**
|
|
7040
|
-
* Get the `AbstractControl` at the given `index` in the array.
|
|
7041
|
-
*
|
|
7042
|
-
* @param index Index in the array to retrieve the control. If `index` is negative, it will wrap
|
|
7043
|
-
* around from the back, and if index is greatly negative (less than `-length`), the result is
|
|
7044
|
-
* undefined. This behavior is the same as `Array.at(index)`.
|
|
7045
|
-
*/
|
|
7046
|
-
at(index) {
|
|
7047
|
-
return this.controls[this._adjustIndex(index)];
|
|
7048
|
-
}
|
|
7049
|
-
/**
|
|
7050
|
-
* Insert a new `AbstractControl` at the end of the array.
|
|
7051
|
-
*
|
|
7052
|
-
* @param control Form control to be inserted
|
|
7053
|
-
* @param options Specifies whether this FormArray instance should emit events after a new
|
|
7054
|
-
* control is added.
|
|
7055
|
-
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
|
7056
|
-
* `valueChanges` observables emit events with the latest status and value when the control is
|
|
7057
|
-
* inserted. When false, no events are emitted.
|
|
7058
|
-
*/
|
|
7059
|
-
push(control, options = {}) {
|
|
7060
|
-
if (Array.isArray(control)) {
|
|
7061
|
-
control.forEach((ctrl) => {
|
|
7062
|
-
this.controls.push(ctrl);
|
|
7063
|
-
this._registerControl(ctrl);
|
|
7064
|
-
});
|
|
7065
|
-
}
|
|
7066
|
-
else {
|
|
7067
|
-
this.controls.push(control);
|
|
7068
|
-
this._registerControl(control);
|
|
7069
|
-
}
|
|
7070
|
-
this.updateValueAndValidity({ emitEvent: options.emitEvent });
|
|
7071
|
-
this._onCollectionChange();
|
|
7072
|
-
}
|
|
7210
|
+
class EmailValidator extends AbstractValidatorDirective {
|
|
7073
7211
|
/**
|
|
7074
|
-
*
|
|
7075
|
-
*
|
|
7076
|
-
* @param index Index in the array to insert the control. If `index` is negative, wraps around
|
|
7077
|
-
* from the back. If `index` is greatly negative (less than `-length`), prepends to the array.
|
|
7078
|
-
* This behavior is the same as `Array.splice(index, 0, control)`.
|
|
7079
|
-
* @param control Form control to be inserted
|
|
7080
|
-
* @param options Specifies whether this FormArray instance should emit events after a new
|
|
7081
|
-
* control is inserted.
|
|
7082
|
-
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
|
7083
|
-
* `valueChanges` observables emit events with the latest status and value when the control is
|
|
7084
|
-
* inserted. When false, no events are emitted.
|
|
7212
|
+
* @description
|
|
7213
|
+
* Tracks changes to the email attribute bound to this directive.
|
|
7085
7214
|
*/
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
|
|
7215
|
+
email;
|
|
7216
|
+
/** @internal */
|
|
7217
|
+
inputName = 'email';
|
|
7218
|
+
/** @internal */
|
|
7219
|
+
normalizeInput = booleanAttribute;
|
|
7220
|
+
/** @internal */
|
|
7221
|
+
createValidator = (input) => emailValidator;
|
|
7222
|
+
/** @docs-private */
|
|
7223
|
+
enabled(input) {
|
|
7224
|
+
return input;
|
|
7090
7225
|
}
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
this.updateValueAndValidity({ emitEvent: options.emitEvent });
|
|
7139
|
-
this._onCollectionChange();
|
|
7140
|
-
}
|
|
7141
|
-
/**
|
|
7142
|
-
* Length of the control array.
|
|
7143
|
-
*/
|
|
7144
|
-
get length() {
|
|
7145
|
-
return this.controls.length;
|
|
7146
|
-
}
|
|
7147
|
-
/**
|
|
7148
|
-
* Sets the value of the `FormArray`. It accepts an array that matches
|
|
7149
|
-
* the structure of the control.
|
|
7150
|
-
*
|
|
7151
|
-
* This method performs strict checks, and throws an error if you try
|
|
7152
|
-
* to set the value of a control that doesn't exist or if you exclude the
|
|
7153
|
-
* value of a control.
|
|
7154
|
-
*
|
|
7155
|
-
* @usageNotes
|
|
7156
|
-
* ### Set the values for the controls in the form array
|
|
7157
|
-
*
|
|
7158
|
-
* ```ts
|
|
7159
|
-
* const arr = new FormArray([
|
|
7160
|
-
* new FormControl(),
|
|
7161
|
-
* new FormControl()
|
|
7162
|
-
* ]);
|
|
7163
|
-
* console.log(arr.value); // [null, null]
|
|
7164
|
-
*
|
|
7165
|
-
* arr.setValue(['Nancy', 'Drew']);
|
|
7166
|
-
* console.log(arr.value); // ['Nancy', 'Drew']
|
|
7167
|
-
* ```
|
|
7168
|
-
*
|
|
7169
|
-
* @param value Array of values for the controls
|
|
7170
|
-
* @param options Configure options that determine how the control propagates changes and
|
|
7171
|
-
* emits events after the value changes
|
|
7172
|
-
*
|
|
7173
|
-
* * `onlySelf`: When true, each change only affects this control, and not its parent. Default
|
|
7174
|
-
* is false.
|
|
7175
|
-
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
|
7176
|
-
* `valueChanges`
|
|
7177
|
-
* observables emit events with the latest status and value when the control value is updated.
|
|
7178
|
-
* When false, no events are emitted.
|
|
7179
|
-
* The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
|
|
7180
|
-
* updateValueAndValidity} method.
|
|
7181
|
-
*/
|
|
7182
|
-
setValue(value, options = {}) {
|
|
7183
|
-
assertAllValuesPresent(this, false, value);
|
|
7184
|
-
value.forEach((newValue, index) => {
|
|
7185
|
-
assertControlPresent(this, false, index);
|
|
7186
|
-
this.at(index).setValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
|
|
7187
|
-
});
|
|
7188
|
-
this.updateValueAndValidity(options);
|
|
7189
|
-
}
|
|
7190
|
-
/**
|
|
7191
|
-
* Patches the value of the `FormArray`. It accepts an array that matches the
|
|
7192
|
-
* structure of the control, and does its best to match the values to the correct
|
|
7193
|
-
* controls in the group.
|
|
7194
|
-
*
|
|
7195
|
-
* It accepts both super-sets and sub-sets of the array without throwing an error.
|
|
7196
|
-
*
|
|
7197
|
-
* @usageNotes
|
|
7198
|
-
* ### Patch the values for controls in a form array
|
|
7199
|
-
*
|
|
7200
|
-
* ```ts
|
|
7201
|
-
* const arr = new FormArray([
|
|
7202
|
-
* new FormControl(),
|
|
7203
|
-
* new FormControl()
|
|
7204
|
-
* ]);
|
|
7205
|
-
* console.log(arr.value); // [null, null]
|
|
7206
|
-
*
|
|
7207
|
-
* arr.patchValue(['Nancy']);
|
|
7208
|
-
* console.log(arr.value); // ['Nancy', null]
|
|
7209
|
-
* ```
|
|
7210
|
-
*
|
|
7211
|
-
* @param value Array of latest values for the controls
|
|
7212
|
-
* @param options Configure options that determine how the control propagates changes and
|
|
7213
|
-
* emits events after the value changes
|
|
7214
|
-
*
|
|
7215
|
-
* * `onlySelf`: When true, each change only affects this control, and not its parent. Default
|
|
7216
|
-
* is false.
|
|
7217
|
-
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
|
7218
|
-
* `valueChanges` observables emit events with the latest status and value when the control
|
|
7219
|
-
* value is updated. When false, no events are emitted. The configuration options are passed to
|
|
7220
|
-
* the {@link AbstractControl#updateValueAndValidity updateValueAndValidity} method.
|
|
7221
|
-
*/
|
|
7222
|
-
patchValue(value, options = {}) {
|
|
7223
|
-
// Even though the `value` argument type doesn't allow `null` and `undefined` values, the
|
|
7224
|
-
// `patchValue` can be called recursively and inner data structures might have these values,
|
|
7225
|
-
// so we just ignore such cases when a field containing FormArray instance receives `null` or
|
|
7226
|
-
// `undefined` as a value.
|
|
7227
|
-
if (value == null /* both `null` and `undefined` */)
|
|
7228
|
-
return;
|
|
7229
|
-
value.forEach((newValue, index) => {
|
|
7230
|
-
if (this.at(index)) {
|
|
7231
|
-
this.at(index).patchValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
|
|
7232
|
-
}
|
|
7233
|
-
});
|
|
7234
|
-
this.updateValueAndValidity(options);
|
|
7235
|
-
}
|
|
7236
|
-
/**
|
|
7237
|
-
* Resets the `FormArray` and all descendants are marked `pristine` and `untouched`, and the
|
|
7238
|
-
* value of all descendants to null or null maps.
|
|
7239
|
-
*
|
|
7240
|
-
* You reset to a specific form state by passing in an array of states
|
|
7241
|
-
* that matches the structure of the control. The state is a standalone value
|
|
7242
|
-
* or a form state object with both a value and a disabled status.
|
|
7243
|
-
*
|
|
7244
|
-
* @usageNotes
|
|
7245
|
-
* ### Reset the values in a form array
|
|
7246
|
-
*
|
|
7247
|
-
* ```ts
|
|
7248
|
-
* const arr = new FormArray([
|
|
7249
|
-
* new FormControl(),
|
|
7250
|
-
* new FormControl()
|
|
7251
|
-
* ]);
|
|
7252
|
-
* arr.reset(['name', 'last name']);
|
|
7253
|
-
*
|
|
7254
|
-
* console.log(arr.value); // ['name', 'last name']
|
|
7255
|
-
* ```
|
|
7256
|
-
*
|
|
7257
|
-
* ### Reset the values in a form array and the disabled status for the first control
|
|
7258
|
-
*
|
|
7259
|
-
* ```ts
|
|
7260
|
-
* arr.reset([
|
|
7261
|
-
* {value: 'name', disabled: true},
|
|
7262
|
-
* 'last'
|
|
7263
|
-
* ]);
|
|
7264
|
-
*
|
|
7265
|
-
* console.log(arr.value); // ['last']
|
|
7266
|
-
* console.log(arr.at(0).status); // 'DISABLED'
|
|
7267
|
-
* ```
|
|
7268
|
-
*
|
|
7269
|
-
* @param value Array of values for the controls
|
|
7270
|
-
* @param options Configure options that determine how the control propagates changes and
|
|
7271
|
-
* emits events after the value changes
|
|
7272
|
-
*
|
|
7273
|
-
* * `onlySelf`: When true, each change only affects this control, and not its parent. Default
|
|
7274
|
-
* is false.
|
|
7275
|
-
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
|
7276
|
-
* `valueChanges`
|
|
7277
|
-
* observables emit events with the latest status and value when the control is reset.
|
|
7278
|
-
* When false, no events are emitted.
|
|
7279
|
-
* The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
|
|
7280
|
-
* updateValueAndValidity} method.
|
|
7281
|
-
*/
|
|
7282
|
-
reset(value = [], options = {}) {
|
|
7283
|
-
this._forEachChild((control, index) => {
|
|
7284
|
-
control.reset(value[index], { onlySelf: true, emitEvent: options.emitEvent });
|
|
7285
|
-
});
|
|
7286
|
-
this._updatePristine(options, this);
|
|
7287
|
-
this._updateTouched(options, this);
|
|
7288
|
-
this.updateValueAndValidity(options);
|
|
7289
|
-
}
|
|
7290
|
-
/**
|
|
7291
|
-
* The aggregate value of the array, including any disabled controls.
|
|
7292
|
-
*
|
|
7293
|
-
* Reports all values regardless of disabled status.
|
|
7294
|
-
*/
|
|
7295
|
-
getRawValue() {
|
|
7296
|
-
return this.controls.map((control) => control.getRawValue());
|
|
7297
|
-
}
|
|
7298
|
-
/**
|
|
7299
|
-
* Remove all controls in the `FormArray`.
|
|
7300
|
-
*
|
|
7301
|
-
* @param options Specifies whether this FormArray instance should emit events after all
|
|
7302
|
-
* controls are removed.
|
|
7303
|
-
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
|
7304
|
-
* `valueChanges` observables emit events with the latest status and value when all controls
|
|
7305
|
-
* in this FormArray instance are removed. When false, no events are emitted.
|
|
7306
|
-
*
|
|
7307
|
-
* @usageNotes
|
|
7308
|
-
* ### Remove all elements from a FormArray
|
|
7309
|
-
*
|
|
7310
|
-
* ```ts
|
|
7311
|
-
* const arr = new FormArray([
|
|
7312
|
-
* new FormControl(),
|
|
7313
|
-
* new FormControl()
|
|
7314
|
-
* ]);
|
|
7315
|
-
* console.log(arr.length); // 2
|
|
7316
|
-
*
|
|
7317
|
-
* arr.clear();
|
|
7318
|
-
* console.log(arr.length); // 0
|
|
7319
|
-
* ```
|
|
7320
|
-
*
|
|
7321
|
-
* It's a simpler and more efficient alternative to removing all elements one by one:
|
|
7322
|
-
*
|
|
7323
|
-
* ```ts
|
|
7324
|
-
* const arr = new FormArray([
|
|
7325
|
-
* new FormControl(),
|
|
7326
|
-
* new FormControl()
|
|
7327
|
-
* ]);
|
|
7328
|
-
*
|
|
7329
|
-
* while (arr.length) {
|
|
7330
|
-
* arr.removeAt(0);
|
|
7331
|
-
* }
|
|
7332
|
-
* ```
|
|
7333
|
-
*/
|
|
7334
|
-
clear(options = {}) {
|
|
7335
|
-
if (this.controls.length < 1)
|
|
7336
|
-
return;
|
|
7337
|
-
this._forEachChild((control) => control._registerOnCollectionChange(() => { }));
|
|
7338
|
-
this.controls.splice(0);
|
|
7339
|
-
this.updateValueAndValidity({ emitEvent: options.emitEvent });
|
|
7340
|
-
}
|
|
7341
|
-
/**
|
|
7342
|
-
* Adjusts a negative index by summing it with the length of the array. For very negative
|
|
7343
|
-
* indices, the result may remain negative.
|
|
7344
|
-
* @internal
|
|
7226
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: EmailValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
7227
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: EmailValidator, isStandalone: false, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: { email: "email" }, providers: [EMAIL_VALIDATOR], usesInheritance: true, ngImport: i0 });
|
|
7228
|
+
}
|
|
7229
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: EmailValidator, decorators: [{
|
|
7230
|
+
type: Directive,
|
|
7231
|
+
args: [{
|
|
7232
|
+
selector: '[email][formControlName],[email][formControl],[email][ngModel]',
|
|
7233
|
+
providers: [EMAIL_VALIDATOR],
|
|
7234
|
+
standalone: false,
|
|
7235
|
+
}]
|
|
7236
|
+
}], propDecorators: { email: [{
|
|
7237
|
+
type: Input
|
|
7238
|
+
}] } });
|
|
7239
|
+
/**
|
|
7240
|
+
* @description
|
|
7241
|
+
* Provider which adds `MinLengthValidator` to the `NG_VALIDATORS` multi-provider list.
|
|
7242
|
+
*/
|
|
7243
|
+
const MIN_LENGTH_VALIDATOR = {
|
|
7244
|
+
provide: NG_VALIDATORS,
|
|
7245
|
+
useExisting: forwardRef(() => MinLengthValidator),
|
|
7246
|
+
multi: true,
|
|
7247
|
+
};
|
|
7248
|
+
/**
|
|
7249
|
+
* A directive that adds minimum length validation to controls marked with the
|
|
7250
|
+
* `minlength` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
|
7251
|
+
*
|
|
7252
|
+
* @see [Form Validation](guide/forms/form-validation)
|
|
7253
|
+
*
|
|
7254
|
+
* @usageNotes
|
|
7255
|
+
*
|
|
7256
|
+
* ### Adding a minimum length validator
|
|
7257
|
+
*
|
|
7258
|
+
* The following example shows how to add a minimum length validator to an input attached to an
|
|
7259
|
+
* ngModel binding.
|
|
7260
|
+
*
|
|
7261
|
+
* ```html
|
|
7262
|
+
* <input name="firstName" ngModel minlength="4">
|
|
7263
|
+
* ```
|
|
7264
|
+
*
|
|
7265
|
+
* @ngModule ReactiveFormsModule
|
|
7266
|
+
* @ngModule FormsModule
|
|
7267
|
+
* @publicApi
|
|
7268
|
+
*/
|
|
7269
|
+
class MinLengthValidator extends AbstractValidatorDirective {
|
|
7270
|
+
/**
|
|
7271
|
+
* @description
|
|
7272
|
+
* Tracks changes to the minimum length bound to this directive.
|
|
7345
7273
|
*/
|
|
7346
|
-
|
|
7347
|
-
return index < 0 ? index + this.length : index;
|
|
7348
|
-
}
|
|
7349
|
-
/** @internal */
|
|
7350
|
-
_syncPendingControls() {
|
|
7351
|
-
let subtreeUpdated = this.controls.reduce((updated, child) => {
|
|
7352
|
-
return child._syncPendingControls() ? true : updated;
|
|
7353
|
-
}, false);
|
|
7354
|
-
if (subtreeUpdated)
|
|
7355
|
-
this.updateValueAndValidity({ onlySelf: true });
|
|
7356
|
-
return subtreeUpdated;
|
|
7357
|
-
}
|
|
7274
|
+
minlength;
|
|
7358
7275
|
/** @internal */
|
|
7359
|
-
|
|
7360
|
-
this.controls.forEach((control, index) => {
|
|
7361
|
-
cb(control, index);
|
|
7362
|
-
});
|
|
7363
|
-
}
|
|
7276
|
+
inputName = 'minlength';
|
|
7364
7277
|
/** @internal */
|
|
7365
|
-
|
|
7366
|
-
this.value = this.controls
|
|
7367
|
-
.filter((control) => control.enabled || this.disabled)
|
|
7368
|
-
.map((control) => control.value);
|
|
7369
|
-
}
|
|
7278
|
+
normalizeInput = (input) => toInteger(input);
|
|
7370
7279
|
/** @internal */
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
}
|
|
7280
|
+
createValidator = (minlength) => minLengthValidator(minlength);
|
|
7281
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MinLengthValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
7282
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: MinLengthValidator, isStandalone: false, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: { minlength: "minlength" }, host: { properties: { "attr.minlength": "_enabled ? minlength : null" } }, providers: [MIN_LENGTH_VALIDATOR], usesInheritance: true, ngImport: i0 });
|
|
7283
|
+
}
|
|
7284
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MinLengthValidator, decorators: [{
|
|
7285
|
+
type: Directive,
|
|
7286
|
+
args: [{
|
|
7287
|
+
selector: '[minlength][formControlName],[minlength][formControl],[minlength][ngModel]',
|
|
7288
|
+
providers: [MIN_LENGTH_VALIDATOR],
|
|
7289
|
+
host: { '[attr.minlength]': '_enabled ? minlength : null' },
|
|
7290
|
+
standalone: false,
|
|
7291
|
+
}]
|
|
7292
|
+
}], propDecorators: { minlength: [{
|
|
7293
|
+
type: Input
|
|
7294
|
+
}] } });
|
|
7295
|
+
/**
|
|
7296
|
+
* @description
|
|
7297
|
+
* Provider which adds `MaxLengthValidator` to the `NG_VALIDATORS` multi-provider list.
|
|
7298
|
+
*/
|
|
7299
|
+
const MAX_LENGTH_VALIDATOR = {
|
|
7300
|
+
provide: NG_VALIDATORS,
|
|
7301
|
+
useExisting: forwardRef(() => MaxLengthValidator),
|
|
7302
|
+
multi: true,
|
|
7303
|
+
};
|
|
7304
|
+
/**
|
|
7305
|
+
* A directive that adds maximum length validation to controls marked with the
|
|
7306
|
+
* `maxlength` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
|
7307
|
+
*
|
|
7308
|
+
* @see [Form Validation](guide/forms/form-validation)
|
|
7309
|
+
*
|
|
7310
|
+
* @usageNotes
|
|
7311
|
+
*
|
|
7312
|
+
* ### Adding a maximum length validator
|
|
7313
|
+
*
|
|
7314
|
+
* The following example shows how to add a maximum length validator to an input attached to an
|
|
7315
|
+
* ngModel binding.
|
|
7316
|
+
*
|
|
7317
|
+
* ```html
|
|
7318
|
+
* <input name="firstName" ngModel maxlength="25">
|
|
7319
|
+
* ```
|
|
7320
|
+
*
|
|
7321
|
+
* @ngModule ReactiveFormsModule
|
|
7322
|
+
* @ngModule FormsModule
|
|
7323
|
+
* @publicApi
|
|
7324
|
+
*/
|
|
7325
|
+
class MaxLengthValidator extends AbstractValidatorDirective {
|
|
7326
|
+
/**
|
|
7327
|
+
* @description
|
|
7328
|
+
* Tracks changes to the maximum length bound to this directive.
|
|
7329
|
+
*/
|
|
7330
|
+
maxlength;
|
|
7374
7331
|
/** @internal */
|
|
7375
|
-
|
|
7376
|
-
this._forEachChild((control) => this._registerControl(control));
|
|
7377
|
-
}
|
|
7332
|
+
inputName = 'maxlength';
|
|
7378
7333
|
/** @internal */
|
|
7379
|
-
|
|
7380
|
-
for (const control of this.controls) {
|
|
7381
|
-
if (control.enabled)
|
|
7382
|
-
return false;
|
|
7383
|
-
}
|
|
7384
|
-
return this.controls.length > 0 || this.disabled;
|
|
7385
|
-
}
|
|
7386
|
-
_registerControl(control) {
|
|
7387
|
-
control.setParent(this);
|
|
7388
|
-
control._registerOnCollectionChange(this._onCollectionChange);
|
|
7389
|
-
}
|
|
7334
|
+
normalizeInput = (input) => toInteger(input);
|
|
7390
7335
|
/** @internal */
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
}
|
|
7336
|
+
createValidator = (maxlength) => maxLengthValidator(maxlength);
|
|
7337
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MaxLengthValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
7338
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: MaxLengthValidator, isStandalone: false, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: { maxlength: "maxlength" }, host: { properties: { "attr.maxlength": "_enabled ? maxlength : null" } }, providers: [MAX_LENGTH_VALIDATOR], usesInheritance: true, ngImport: i0 });
|
|
7394
7339
|
}
|
|
7395
|
-
|
|
7340
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MaxLengthValidator, decorators: [{
|
|
7341
|
+
type: Directive,
|
|
7342
|
+
args: [{
|
|
7343
|
+
selector: '[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]',
|
|
7344
|
+
providers: [MAX_LENGTH_VALIDATOR],
|
|
7345
|
+
host: { '[attr.maxlength]': '_enabled ? maxlength : null' },
|
|
7346
|
+
standalone: false,
|
|
7347
|
+
}]
|
|
7348
|
+
}], propDecorators: { maxlength: [{
|
|
7349
|
+
type: Input
|
|
7350
|
+
}] } });
|
|
7396
7351
|
/**
|
|
7397
7352
|
* @description
|
|
7398
|
-
*
|
|
7353
|
+
* Provider which adds `PatternValidator` to the `NG_VALIDATORS` multi-provider list.
|
|
7354
|
+
*/
|
|
7355
|
+
const PATTERN_VALIDATOR = {
|
|
7356
|
+
provide: NG_VALIDATORS,
|
|
7357
|
+
useExisting: forwardRef(() => PatternValidator),
|
|
7358
|
+
multi: true,
|
|
7359
|
+
};
|
|
7360
|
+
/**
|
|
7361
|
+
* @description
|
|
7362
|
+
* A directive that adds regex pattern validation to controls marked with the
|
|
7363
|
+
* `pattern` attribute. The regex must match the entire control value.
|
|
7364
|
+
* The directive is provided with the `NG_VALIDATORS` multi-provider list.
|
|
7365
|
+
*
|
|
7366
|
+
* @see [Form Validation](guide/forms/form-validation)
|
|
7367
|
+
*
|
|
7368
|
+
* @usageNotes
|
|
7369
|
+
*
|
|
7370
|
+
* ### Adding a pattern validator
|
|
7399
7371
|
*
|
|
7372
|
+
* The following example shows how to add a pattern validator to an input attached to an
|
|
7373
|
+
* ngModel binding.
|
|
7374
|
+
*
|
|
7375
|
+
* ```html
|
|
7376
|
+
* <input name="firstName" ngModel pattern="[a-zA-Z ]*">
|
|
7377
|
+
* ```
|
|
7378
|
+
*
|
|
7379
|
+
* @ngModule ReactiveFormsModule
|
|
7380
|
+
* @ngModule FormsModule
|
|
7400
7381
|
* @publicApi
|
|
7401
7382
|
*/
|
|
7402
|
-
|
|
7383
|
+
class PatternValidator extends AbstractValidatorDirective {
|
|
7384
|
+
/**
|
|
7385
|
+
* @description
|
|
7386
|
+
* Tracks changes to the pattern bound to this directive.
|
|
7387
|
+
*/
|
|
7388
|
+
pattern; // This input is always defined, since the name matches selector.
|
|
7389
|
+
/** @internal */
|
|
7390
|
+
inputName = 'pattern';
|
|
7391
|
+
/** @internal */
|
|
7392
|
+
normalizeInput = (input) => input;
|
|
7393
|
+
/** @internal */
|
|
7394
|
+
createValidator = (input) => patternValidator(input);
|
|
7395
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: PatternValidator, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
7396
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: PatternValidator, isStandalone: false, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: { pattern: "pattern" }, host: { properties: { "attr.pattern": "_enabled ? pattern : null" } }, providers: [PATTERN_VALIDATOR], usesInheritance: true, ngImport: i0 });
|
|
7397
|
+
}
|
|
7398
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: PatternValidator, decorators: [{
|
|
7399
|
+
type: Directive,
|
|
7400
|
+
args: [{
|
|
7401
|
+
selector: '[pattern][formControlName],[pattern][formControl],[pattern][ngModel]',
|
|
7402
|
+
providers: [PATTERN_VALIDATOR],
|
|
7403
|
+
host: { '[attr.pattern]': '_enabled ? pattern : null' },
|
|
7404
|
+
standalone: false,
|
|
7405
|
+
}]
|
|
7406
|
+
}], propDecorators: { pattern: [{
|
|
7407
|
+
type: Input
|
|
7408
|
+
}] } });
|
|
7409
|
+
|
|
7410
|
+
const SHARED_FORM_DIRECTIVES = [
|
|
7411
|
+
ɵNgNoValidate,
|
|
7412
|
+
NgSelectOption,
|
|
7413
|
+
ɵNgSelectMultipleOption,
|
|
7414
|
+
DefaultValueAccessor,
|
|
7415
|
+
NumberValueAccessor,
|
|
7416
|
+
RangeValueAccessor,
|
|
7417
|
+
CheckboxControlValueAccessor,
|
|
7418
|
+
SelectControlValueAccessor,
|
|
7419
|
+
SelectMultipleControlValueAccessor,
|
|
7420
|
+
RadioControlValueAccessor,
|
|
7421
|
+
NgControlStatus,
|
|
7422
|
+
NgControlStatusGroup,
|
|
7423
|
+
RequiredValidator,
|
|
7424
|
+
MinLengthValidator,
|
|
7425
|
+
MaxLengthValidator,
|
|
7426
|
+
PatternValidator,
|
|
7427
|
+
CheckboxRequiredValidator,
|
|
7428
|
+
EmailValidator,
|
|
7429
|
+
MinValidator,
|
|
7430
|
+
MaxValidator,
|
|
7431
|
+
];
|
|
7432
|
+
const TEMPLATE_DRIVEN_DIRECTIVES = [NgModel, NgModelGroup, NgForm];
|
|
7433
|
+
const REACTIVE_DRIVEN_DIRECTIVES = [
|
|
7434
|
+
FormControlDirective,
|
|
7435
|
+
FormGroupDirective,
|
|
7436
|
+
FormArrayDirective,
|
|
7437
|
+
FormControlName,
|
|
7438
|
+
FormGroupName,
|
|
7439
|
+
FormArrayName,
|
|
7440
|
+
];
|
|
7441
|
+
/**
|
|
7442
|
+
* Internal module used for sharing directives between FormsModule and ReactiveFormsModule
|
|
7443
|
+
*/
|
|
7444
|
+
class ɵInternalFormsSharedModule {
|
|
7445
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ɵInternalFormsSharedModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
7446
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.2.0-next.2", ngImport: i0, type: ɵInternalFormsSharedModule, declarations: [ɵNgNoValidate,
|
|
7447
|
+
NgSelectOption,
|
|
7448
|
+
ɵNgSelectMultipleOption,
|
|
7449
|
+
DefaultValueAccessor,
|
|
7450
|
+
NumberValueAccessor,
|
|
7451
|
+
RangeValueAccessor,
|
|
7452
|
+
CheckboxControlValueAccessor,
|
|
7453
|
+
SelectControlValueAccessor,
|
|
7454
|
+
SelectMultipleControlValueAccessor,
|
|
7455
|
+
RadioControlValueAccessor,
|
|
7456
|
+
NgControlStatus,
|
|
7457
|
+
NgControlStatusGroup,
|
|
7458
|
+
RequiredValidator,
|
|
7459
|
+
MinLengthValidator,
|
|
7460
|
+
MaxLengthValidator,
|
|
7461
|
+
PatternValidator,
|
|
7462
|
+
CheckboxRequiredValidator,
|
|
7463
|
+
EmailValidator,
|
|
7464
|
+
MinValidator,
|
|
7465
|
+
MaxValidator], exports: [ɵNgNoValidate,
|
|
7466
|
+
NgSelectOption,
|
|
7467
|
+
ɵNgSelectMultipleOption,
|
|
7468
|
+
DefaultValueAccessor,
|
|
7469
|
+
NumberValueAccessor,
|
|
7470
|
+
RangeValueAccessor,
|
|
7471
|
+
CheckboxControlValueAccessor,
|
|
7472
|
+
SelectControlValueAccessor,
|
|
7473
|
+
SelectMultipleControlValueAccessor,
|
|
7474
|
+
RadioControlValueAccessor,
|
|
7475
|
+
NgControlStatus,
|
|
7476
|
+
NgControlStatusGroup,
|
|
7477
|
+
RequiredValidator,
|
|
7478
|
+
MinLengthValidator,
|
|
7479
|
+
MaxLengthValidator,
|
|
7480
|
+
PatternValidator,
|
|
7481
|
+
CheckboxRequiredValidator,
|
|
7482
|
+
EmailValidator,
|
|
7483
|
+
MinValidator,
|
|
7484
|
+
MaxValidator] });
|
|
7485
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ɵInternalFormsSharedModule });
|
|
7486
|
+
}
|
|
7487
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ɵInternalFormsSharedModule, decorators: [{
|
|
7488
|
+
type: NgModule,
|
|
7489
|
+
args: [{
|
|
7490
|
+
declarations: SHARED_FORM_DIRECTIVES,
|
|
7491
|
+
exports: SHARED_FORM_DIRECTIVES,
|
|
7492
|
+
}]
|
|
7493
|
+
}] });
|
|
7403
7494
|
|
|
7404
7495
|
function isAbstractControlOptions(options) {
|
|
7405
7496
|
return (!!options &&
|
|
@@ -7651,7 +7742,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2",
|
|
|
7651
7742
|
/**
|
|
7652
7743
|
* @publicApi
|
|
7653
7744
|
*/
|
|
7654
|
-
const VERSION = new Version('21.0.0-next.
|
|
7745
|
+
const VERSION = new Version('21.0.0-next.1');
|
|
7655
7746
|
|
|
7656
7747
|
/**
|
|
7657
7748
|
* Exports the required providers and directives for template-driven forms,
|
|
@@ -7729,7 +7820,7 @@ class ReactiveFormsModule {
|
|
|
7729
7820
|
};
|
|
7730
7821
|
}
|
|
7731
7822
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ReactiveFormsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
7732
|
-
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.2.0-next.2", ngImport: i0, type: ReactiveFormsModule, declarations: [FormControlDirective, FormGroupDirective, FormControlName, FormGroupName, FormArrayName], exports: [ɵInternalFormsSharedModule, FormControlDirective, FormGroupDirective, FormControlName, FormGroupName, FormArrayName] });
|
|
7823
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.2.0-next.2", ngImport: i0, type: ReactiveFormsModule, declarations: [FormControlDirective, FormGroupDirective, FormArrayDirective, FormControlName, FormGroupName, FormArrayName], exports: [ɵInternalFormsSharedModule, FormControlDirective, FormGroupDirective, FormArrayDirective, FormControlName, FormGroupName, FormArrayName] });
|
|
7733
7824
|
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ReactiveFormsModule, imports: [ɵInternalFormsSharedModule] });
|
|
7734
7825
|
}
|
|
7735
7826
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ReactiveFormsModule, decorators: [{
|
|
@@ -7740,5 +7831,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2",
|
|
|
7740
7831
|
}]
|
|
7741
7832
|
}] });
|
|
7742
7833
|
|
|
7743
|
-
export { AbstractControl, AbstractControlDirective, AbstractFormGroupDirective, COMPOSITION_BUFFER_MODE, CheckboxControlValueAccessor, CheckboxRequiredValidator, ControlContainer, ControlEvent, DefaultValueAccessor, EmailValidator, FormArray, FormArrayName, FormBuilder, FormControl, FormControlDirective, FormControlName, FormGroup, FormGroupDirective, FormGroupName, FormRecord, FormResetEvent, FormSubmittedEvent, FormsModule, MaxLengthValidator, MaxValidator, MinLengthValidator, MinValidator, NG_ASYNC_VALIDATORS, NG_VALIDATORS, NG_VALUE_ACCESSOR, NgControl, NgControlStatus, NgControlStatusGroup, NgForm, NgModel, NgModelGroup, NgSelectOption, NonNullableFormBuilder, NumberValueAccessor, PatternValidator, PristineChangeEvent, RadioControlValueAccessor, RangeValueAccessor, ReactiveFormsModule, RequiredValidator, SelectControlValueAccessor, SelectMultipleControlValueAccessor, StatusChangeEvent, TouchedChangeEvent, UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, VERSION, Validators, ValueChangeEvent, isFormArray, isFormControl, isFormGroup, isFormRecord, ɵInternalFormsSharedModule, ɵNgNoValidate, ɵNgSelectMultipleOption };
|
|
7834
|
+
export { AbstractControl, AbstractControlDirective, AbstractFormDirective, AbstractFormGroupDirective, COMPOSITION_BUFFER_MODE, CheckboxControlValueAccessor, CheckboxRequiredValidator, ControlContainer, ControlEvent, DefaultValueAccessor, EmailValidator, FormArray, FormArrayDirective, FormArrayName, FormBuilder, FormControl, FormControlDirective, FormControlName, FormGroup, FormGroupDirective, FormGroupName, FormRecord, FormResetEvent, FormSubmittedEvent, FormsModule, MaxLengthValidator, MaxValidator, MinLengthValidator, MinValidator, NG_ASYNC_VALIDATORS, NG_VALIDATORS, NG_VALUE_ACCESSOR, NgControl, NgControlStatus, NgControlStatusGroup, NgForm, NgModel, NgModelGroup, NgSelectOption, NonNullableFormBuilder, NumberValueAccessor, PatternValidator, PristineChangeEvent, RadioControlValueAccessor, RangeValueAccessor, ReactiveFormsModule, RequiredValidator, SelectControlValueAccessor, SelectMultipleControlValueAccessor, StatusChangeEvent, TouchedChangeEvent, UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, VERSION, Validators, ValueChangeEvent, isFormArray, isFormControl, isFormGroup, isFormRecord, ɵInternalFormsSharedModule, ɵNgNoValidate, ɵNgSelectMultipleOption };
|
|
7744
7835
|
//# sourceMappingURL=forms.mjs.map
|