@quadrel-enterprise-ui/framework 20.21.0 → 20.21.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/quadrel-enterprise-ui-framework.mjs +243 -28
- package/fesm2022/quadrel-enterprise-ui-framework.mjs.map +1 -1
- package/index.d.ts +191 -19
- package/package.json +1 -1
- package/src/assets/i18n/de.json +1 -0
- package/src/assets/i18n/en.json +1 -0
- package/src/assets/i18n/fr.json +1 -0
- package/src/assets/i18n/it.json +1 -0
|
@@ -8468,6 +8468,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
8468
8468
|
// @ts-strict-ignore
|
|
8469
8469
|
class QdFormControl extends UntypedFormControl {
|
|
8470
8470
|
maxLength;
|
|
8471
|
+
revalidationPartners = [];
|
|
8471
8472
|
validatorList;
|
|
8472
8473
|
constructor(formState, validatorOrOpts, asyncValidator) {
|
|
8473
8474
|
super(formState, validatorOrOpts, asyncValidator);
|
|
@@ -8482,12 +8483,15 @@ class QdFormControl extends UntypedFormControl {
|
|
|
8482
8483
|
}
|
|
8483
8484
|
setPropsFromValidatorList() {
|
|
8484
8485
|
let maxLength;
|
|
8486
|
+
const revalidationPartners = [];
|
|
8485
8487
|
this.validatorList.forEach((validatorFn) => {
|
|
8486
|
-
if (validatorFn.maxLength)
|
|
8488
|
+
if (validatorFn.maxLength)
|
|
8487
8489
|
maxLength = validatorFn.maxLength;
|
|
8488
|
-
|
|
8490
|
+
if (validatorFn.qdRevalidates)
|
|
8491
|
+
revalidationPartners.push(validatorFn.qdRevalidates);
|
|
8489
8492
|
});
|
|
8490
8493
|
this.maxLength = maxLength;
|
|
8494
|
+
this.revalidationPartners = revalidationPartners;
|
|
8491
8495
|
}
|
|
8492
8496
|
setValidators(validators) {
|
|
8493
8497
|
this.validatorList = this.getValidatorList(validators);
|
|
@@ -8520,6 +8524,9 @@ class QdFormControl extends UntypedFormControl {
|
|
|
8520
8524
|
getMaxLengthOrUndefined() {
|
|
8521
8525
|
return this.maxLength;
|
|
8522
8526
|
}
|
|
8527
|
+
getRevalidationPartners() {
|
|
8528
|
+
return this.revalidationPartners;
|
|
8529
|
+
}
|
|
8523
8530
|
}
|
|
8524
8531
|
function isOptionsObj$1(validatorOrOpts) {
|
|
8525
8532
|
return validatorOrOpts != null && !Array.isArray(validatorOrOpts) && typeof validatorOrOpts === 'object';
|
|
@@ -12387,6 +12394,8 @@ class QdDatepickerComponent {
|
|
|
12387
12394
|
const current = this.config?.disabledDates;
|
|
12388
12395
|
if (current === this._boundDisabledDates)
|
|
12389
12396
|
return;
|
|
12397
|
+
if (!this.control)
|
|
12398
|
+
return;
|
|
12390
12399
|
this._boundDisabledDates = current;
|
|
12391
12400
|
this.validateDisabledDates();
|
|
12392
12401
|
}
|
|
@@ -12394,6 +12403,8 @@ class QdDatepickerComponent {
|
|
|
12394
12403
|
const current = this.config?.timePicker?.disabledTimes;
|
|
12395
12404
|
if (current === this._boundDisabledTimes)
|
|
12396
12405
|
return;
|
|
12406
|
+
if (!this.control)
|
|
12407
|
+
return;
|
|
12397
12408
|
this._boundDisabledTimes = current;
|
|
12398
12409
|
this.validateDisabledTimes();
|
|
12399
12410
|
}
|
|
@@ -13524,14 +13535,40 @@ const validatorsDroppedWithOptsWarning = 'Quadrel Framework | QdForms - QdFormCo
|
|
|
13524
13535
|
function hasUnit(control) {
|
|
13525
13536
|
return control.value?.value != null && control.value?.unit != null;
|
|
13526
13537
|
}
|
|
13538
|
+
/**
|
|
13539
|
+
* Ready-to-use validators for Quadrel Reactive Forms.
|
|
13540
|
+
*
|
|
13541
|
+
* Use them like Angular's built-in `Validators`, but every validator returns a **translatable
|
|
13542
|
+
* error key** instead of a fixed message, and most accept a custom `errorKey` as the last
|
|
13543
|
+
* argument.
|
|
13544
|
+
*
|
|
13545
|
+
* Empty values pass for most validators — combine with `required()` when a value is mandatory.
|
|
13546
|
+
* The amount-aware validators (`min`, `max`, `minLength`, `maxLength`, `pattern`) also accept
|
|
13547
|
+
* `{ value, unit }` objects and validate the inner `value`.
|
|
13548
|
+
*
|
|
13549
|
+
* #### **Usage**
|
|
13550
|
+
* ```ts
|
|
13551
|
+
* form = new QdFormGroup({
|
|
13552
|
+
* email: new QdFormControl(null, [QdValidators.required(), QdValidators.email()]),
|
|
13553
|
+
* age: new QdFormControl(null, [QdValidators.required(), QdValidators.min(18)])
|
|
13554
|
+
* });
|
|
13555
|
+
* ```
|
|
13556
|
+
*/
|
|
13527
13557
|
class QdValidators {
|
|
13528
13558
|
/**
|
|
13529
|
-
* Validates that
|
|
13559
|
+
* Validates that a numeric value is greater than or equal to a minimum.
|
|
13560
|
+
*
|
|
13561
|
+
* Empty values (`null`/`undefined`) pass — combine with `required` when a value is mandatory.
|
|
13562
|
+
* Also accepts amount objects of the shape `{ value, unit }`; in that case the inner `value`
|
|
13563
|
+
* is validated.
|
|
13564
|
+
*
|
|
13565
|
+
* @param min - The smallest allowed value (inclusive).
|
|
13566
|
+
* @param errorKey - Translation key returned when the value is below the minimum.
|
|
13530
13567
|
*
|
|
13531
13568
|
* #### **Usage**
|
|
13532
13569
|
* ```ts
|
|
13533
|
-
* new QdFormControl(
|
|
13534
|
-
* new QdFormControl(
|
|
13570
|
+
* new QdFormControl(null, QdValidators.min(3));
|
|
13571
|
+
* new QdFormControl(null, QdValidators.min(3, 'custom-error'));
|
|
13535
13572
|
* ```
|
|
13536
13573
|
*/
|
|
13537
13574
|
static min(min, errorKey = 'i18n.qd.form.error.min') {
|
|
@@ -13543,12 +13580,19 @@ class QdValidators {
|
|
|
13543
13580
|
return validFn;
|
|
13544
13581
|
}
|
|
13545
13582
|
/**
|
|
13546
|
-
* Validates that
|
|
13583
|
+
* Validates that a numeric value is less than or equal to a maximum.
|
|
13584
|
+
*
|
|
13585
|
+
* Empty values (`null`/`undefined`) pass — combine with `required` when a value is mandatory.
|
|
13586
|
+
* Also accepts amount objects of the shape `{ value, unit }`; in that case the inner `value`
|
|
13587
|
+
* is validated.
|
|
13588
|
+
*
|
|
13589
|
+
* @param max - The largest allowed value (inclusive).
|
|
13590
|
+
* @param errorKey - Translation key returned when the value exceeds the maximum.
|
|
13547
13591
|
*
|
|
13548
13592
|
* #### **Usage**
|
|
13549
13593
|
* ```ts
|
|
13550
|
-
* new QdFormControl(
|
|
13551
|
-
* new QdFormControl(
|
|
13594
|
+
* new QdFormControl(null, QdValidators.max(10));
|
|
13595
|
+
* new QdFormControl(null, QdValidators.max(10, 'custom-error'));
|
|
13552
13596
|
* ```
|
|
13553
13597
|
*/
|
|
13554
13598
|
static max(max, errorKey = 'i18n.qd.form.error.max') {
|
|
@@ -13560,7 +13604,16 @@ class QdValidators {
|
|
|
13560
13604
|
return validFn;
|
|
13561
13605
|
}
|
|
13562
13606
|
/**
|
|
13563
|
-
*
|
|
13607
|
+
* Validates that the field holds a non-empty value.
|
|
13608
|
+
*
|
|
13609
|
+
* Quadrel form components additionally render a required asterisk (`*`) on the field label
|
|
13610
|
+
* whenever this validator is present, so users see at a glance that the field is mandatory.
|
|
13611
|
+
*
|
|
13612
|
+
* Empty means: `null`, `undefined`, an empty string, an empty array, or an object whose
|
|
13613
|
+
* leaf values are all empty (checked recursively — useful for amount objects such as
|
|
13614
|
+
* `{ value, unit }`).
|
|
13615
|
+
*
|
|
13616
|
+
* @param errorKey - Translation key returned when the field is empty.
|
|
13564
13617
|
*
|
|
13565
13618
|
* #### **Usage**
|
|
13566
13619
|
* ```ts
|
|
@@ -13583,7 +13636,12 @@ class QdValidators {
|
|
|
13583
13636
|
return value == null || (typeof value === 'string' && value.length === 0);
|
|
13584
13637
|
}
|
|
13585
13638
|
/**
|
|
13586
|
-
* Validates that the
|
|
13639
|
+
* Validates that the field contains a single, well-formed email address.
|
|
13640
|
+
*
|
|
13641
|
+
* Empty values pass — combine with `required` when an address is mandatory. The whole value
|
|
13642
|
+
* must be the address; surrounding text makes it invalid.
|
|
13643
|
+
*
|
|
13644
|
+
* @param errorKey - Translation key returned when the address is malformed.
|
|
13587
13645
|
*
|
|
13588
13646
|
* #### **Usage**
|
|
13589
13647
|
* ```ts
|
|
@@ -13598,7 +13656,14 @@ class QdValidators {
|
|
|
13598
13656
|
return validFn;
|
|
13599
13657
|
}
|
|
13600
13658
|
/**
|
|
13601
|
-
*
|
|
13659
|
+
* Validates that a text value is at least a given number of characters long.
|
|
13660
|
+
*
|
|
13661
|
+
* Empty values (`null`/`undefined`/`''`) pass — combine with `required` when input is
|
|
13662
|
+
* mandatory. Also accepts amount objects of the shape `{ value, unit }`; in that case the
|
|
13663
|
+
* inner `value` is measured.
|
|
13664
|
+
*
|
|
13665
|
+
* @param minLength - The minimum number of characters (inclusive).
|
|
13666
|
+
* @param errorKey - Translation key returned when the value is too short.
|
|
13602
13667
|
*
|
|
13603
13668
|
* #### **Usage**
|
|
13604
13669
|
* ```ts
|
|
@@ -13615,7 +13680,15 @@ class QdValidators {
|
|
|
13615
13680
|
return validFn;
|
|
13616
13681
|
}
|
|
13617
13682
|
/**
|
|
13618
|
-
*
|
|
13683
|
+
* Validates that a text value is no longer than a given number of characters.
|
|
13684
|
+
*
|
|
13685
|
+
* Empty values pass — combine with `required` when input is mandatory. Also accepts amount
|
|
13686
|
+
* objects of the shape `{ value, unit }`; in that case the inner `value` is measured. The
|
|
13687
|
+
* configured limit is exposed as `.maxLength` on the returned validator, which `qd-textarea`
|
|
13688
|
+
* reads to show a live character counter (`current / max`).
|
|
13689
|
+
*
|
|
13690
|
+
* @param maxLength - The maximum number of characters (inclusive).
|
|
13691
|
+
* @param errorKey - Translation key returned when the value is too long.
|
|
13619
13692
|
*
|
|
13620
13693
|
* #### **Usage**
|
|
13621
13694
|
* ```ts
|
|
@@ -13633,7 +13706,13 @@ class QdValidators {
|
|
|
13633
13706
|
return validFn;
|
|
13634
13707
|
}
|
|
13635
13708
|
/**
|
|
13636
|
-
*
|
|
13709
|
+
* Validates that a text value matches a regular expression.
|
|
13710
|
+
*
|
|
13711
|
+
* Empty values pass — combine with `required` when input is mandatory. Also accepts amount
|
|
13712
|
+
* objects of the shape `{ value, unit }`; in that case the inner `value` is matched.
|
|
13713
|
+
*
|
|
13714
|
+
* @param pattern - The pattern to match, as a `RegExp` or a string regular expression.
|
|
13715
|
+
* @param errorKey - Translation key returned when the value does not match.
|
|
13637
13716
|
*
|
|
13638
13717
|
* #### **Usage**
|
|
13639
13718
|
* ```ts
|
|
@@ -13651,11 +13730,17 @@ class QdValidators {
|
|
|
13651
13730
|
return validFn;
|
|
13652
13731
|
}
|
|
13653
13732
|
/**
|
|
13654
|
-
*
|
|
13733
|
+
* Validates that the value is a real, parseable `Date` object.
|
|
13734
|
+
*
|
|
13735
|
+
* Empty values pass — combine with `required` when a date is mandatory. Strings (including
|
|
13736
|
+
* `'Invalid Date'`), numbers and plain objects are rejected. The error carries the locale
|
|
13737
|
+
* date format (`DD.MM.YYYY`) as a `params.format` hint for the message.
|
|
13738
|
+
*
|
|
13739
|
+
* @param errorKey - Translation key returned when the value is not a valid date.
|
|
13655
13740
|
*
|
|
13656
13741
|
* #### **Usage**
|
|
13657
13742
|
* ```ts
|
|
13658
|
-
* new QdFormControl(
|
|
13743
|
+
* new QdFormControl(null, QdValidators.date());
|
|
13659
13744
|
* new QdFormControl(new Date(), QdValidators.date());
|
|
13660
13745
|
* new QdFormControl(new Date(), QdValidators.date('date-error'));
|
|
13661
13746
|
* ```
|
|
@@ -13666,24 +13751,29 @@ class QdValidators {
|
|
|
13666
13751
|
return null;
|
|
13667
13752
|
const localizedFormat = moment().format('DD.MM.YYYY');
|
|
13668
13753
|
const formattedErrorKey = { date: { key: errorKey, params: { format: localizedFormat } } };
|
|
13669
|
-
|
|
13670
|
-
return formattedErrorKey;
|
|
13671
|
-
if (!(value instanceof Date) || isNaN(value.getTime()))
|
|
13672
|
-
return formattedErrorKey;
|
|
13673
|
-
return null;
|
|
13754
|
+
return this.isValidDate(value) ? null : formattedErrorKey;
|
|
13674
13755
|
};
|
|
13675
13756
|
}
|
|
13676
13757
|
/**
|
|
13677
|
-
*
|
|
13758
|
+
* Validates that a date does not fall inside any of the given disabled ranges.
|
|
13759
|
+
*
|
|
13760
|
+
* Each range may set `from`, `to`, or both; an open end reaches into the far past/future.
|
|
13761
|
+
* Boundaries are **exclusive** — a date exactly on `from` or `to` is still allowed; only
|
|
13762
|
+
* dates strictly between them are rejected. Comparison is day-granular. Empty or invalid
|
|
13763
|
+
* values pass.
|
|
13764
|
+
*
|
|
13765
|
+
* @param disabledDates - Ranges to block, e.g. `[{ from, to }]`.
|
|
13766
|
+
* @param errorKey - Translation key returned when the date lies inside a range.
|
|
13678
13767
|
*
|
|
13679
13768
|
* #### **Usage**
|
|
13680
13769
|
* ```ts
|
|
13681
|
-
* new QdFormControl(
|
|
13770
|
+
* new QdFormControl(null, QdValidators.disabledDates([{ from: new Date('2025-01-01') }]));
|
|
13771
|
+
* new QdFormControl(null, QdValidators.disabledDates([{ from: new Date('2025-01-01'), to: new Date('2025-01-31') }]));
|
|
13682
13772
|
* ```
|
|
13683
13773
|
*/
|
|
13684
13774
|
static disabledDates(disabledDates, errorKey = 'i18n.qd.form.error.disabledDates') {
|
|
13685
13775
|
const validFn = (control) => {
|
|
13686
|
-
if (!
|
|
13776
|
+
if (!this.isValidDate(control.value))
|
|
13687
13777
|
return null;
|
|
13688
13778
|
const date = moment(control.value.getTime());
|
|
13689
13779
|
return this.isDateDisabled(disabledDates, date) ? { disabledDates: errorKey } : null;
|
|
@@ -13702,16 +13792,74 @@ class QdValidators {
|
|
|
13702
13792
|
});
|
|
13703
13793
|
}
|
|
13704
13794
|
/**
|
|
13705
|
-
*
|
|
13795
|
+
* Validates that a date stays on the correct side of a sibling "range partner" control.
|
|
13796
|
+
*
|
|
13797
|
+
* Put it on both ends of a from/to pair, each pointing at the other. A `'start'` control is
|
|
13798
|
+
* invalid when its date is after the partner; an `'end'` control is invalid when its date is
|
|
13799
|
+
* before the partner. Comparison is day-granular, so equal days are valid.
|
|
13800
|
+
*
|
|
13801
|
+
* The partner value is read live on every run, so the limit is never cached — it stays
|
|
13802
|
+
* correct across form rebuilds, saves and config changes. Empty or invalid own/partner
|
|
13803
|
+
* values, and a missing partner control, all pass.
|
|
13804
|
+
*
|
|
13805
|
+
* Inside a `QdFormGroup` the partner is re-validated automatically when this control changes
|
|
13806
|
+
* (and vice versa), so a stale error never lingers — no manual `updateValueAndValidity` needed.
|
|
13807
|
+
* The validator declares this dependency via `qdRevalidates`, which the group reads.
|
|
13808
|
+
*
|
|
13809
|
+
* The auto-revalidation only applies when both controls are `QdFormControl`s inside a
|
|
13810
|
+
* `QdFormGroup`, and only for validators present at construction or set via the group's
|
|
13811
|
+
* `add`/`set`/`removeControl`. On a native `FormGroup`/`FormControl`, or when the validator is
|
|
13812
|
+
* added later via `control.addValidators(...)`, re-validate the partner manually with
|
|
13813
|
+
* `partner.updateValueAndValidity({ emitEvent: false })` whenever this control changes.
|
|
13814
|
+
*
|
|
13815
|
+
* @param partnerControlName - Name of the sibling control holding the other end of the range.
|
|
13816
|
+
* @param position - `'start'` for the from-control, `'end'` for the to-control.
|
|
13817
|
+
* @param errorKey - Translation key returned when the order is violated.
|
|
13818
|
+
*
|
|
13819
|
+
* #### **Usage**
|
|
13820
|
+
* ```ts
|
|
13821
|
+
* new QdFormGroup({
|
|
13822
|
+
* from: new QdFormControl(null, QdValidators.dateRange('to', 'start')),
|
|
13823
|
+
* to: new QdFormControl(null, QdValidators.dateRange('from', 'end'))
|
|
13824
|
+
* });
|
|
13825
|
+
* ```
|
|
13826
|
+
*/
|
|
13827
|
+
static dateRange(partnerControlName, position, errorKey = 'i18n.qd.form.error.dateRange') {
|
|
13828
|
+
const validFn = (control) => {
|
|
13829
|
+
const ownValue = control.value;
|
|
13830
|
+
const partnerValue = control.parent?.get(partnerControlName)?.value;
|
|
13831
|
+
if (!this.isValidDate(ownValue) || !this.isValidDate(partnerValue))
|
|
13832
|
+
return null;
|
|
13833
|
+
const own = moment(ownValue);
|
|
13834
|
+
const partner = moment(partnerValue);
|
|
13835
|
+
const isInvalid = position === 'start' ? own.isAfter(partner, 'day') : own.isBefore(partner, 'day');
|
|
13836
|
+
return isInvalid ? { dateRange: errorKey } : null;
|
|
13837
|
+
};
|
|
13838
|
+
validFn.qdRevalidates = partnerControlName;
|
|
13839
|
+
return validFn;
|
|
13840
|
+
}
|
|
13841
|
+
static isValidDate(value) {
|
|
13842
|
+
return value instanceof Date && !isNaN(value.getTime());
|
|
13843
|
+
}
|
|
13844
|
+
/**
|
|
13845
|
+
* Validates that the time of a date value does not fall inside any disabled time range.
|
|
13846
|
+
*
|
|
13847
|
+
* Each range may set `from`, `to`, or both, as `HH:mm` strings. Boundaries are **exclusive** —
|
|
13848
|
+
* a time exactly on `from` or `to` is allowed; only times strictly between them are rejected.
|
|
13849
|
+
* Only the time-of-day is considered, not the date. Empty or invalid values pass.
|
|
13850
|
+
*
|
|
13851
|
+
* @param disabledTimes - Ranges to block, e.g. `[{ from: '12:00', to: '13:00' }]`.
|
|
13852
|
+
* @param errorKey - Translation key returned when the time lies inside a range.
|
|
13706
13853
|
*
|
|
13707
13854
|
* #### **Usage**
|
|
13708
13855
|
* ```ts
|
|
13709
|
-
* new QdFormControl(
|
|
13856
|
+
* new QdFormControl(null, QdValidators.disabledTimes([{ from: '15:00' }]));
|
|
13857
|
+
* new QdFormControl(null, QdValidators.disabledTimes([{ from: '12:00', to: '13:00' }]));
|
|
13710
13858
|
* ```
|
|
13711
13859
|
*/
|
|
13712
13860
|
static disabledTimes(disabledTimes, errorKey = 'i18n.qd.form.error.disabledTimes') {
|
|
13713
13861
|
const validFn = (control) => {
|
|
13714
|
-
if (!
|
|
13862
|
+
if (!this.isValidDate(control.value))
|
|
13715
13863
|
return null;
|
|
13716
13864
|
const time = moment(control.value).format('HH:mm');
|
|
13717
13865
|
return TimePickerService.isTimeDisabled(time, disabledTimes) ? { disabledTimes: errorKey } : null;
|
|
@@ -13719,7 +13867,14 @@ class QdValidators {
|
|
|
13719
13867
|
return validFn;
|
|
13720
13868
|
}
|
|
13721
13869
|
/**
|
|
13722
|
-
*
|
|
13870
|
+
* Validates that a selected file does not exceed a maximum size.
|
|
13871
|
+
*
|
|
13872
|
+
* Operates on a `File` value (e.g. from a file input). Non-file values — including `null` —
|
|
13873
|
+
* pass, so combine with `required` when a file is mandatory. The error carries `params.maxMb`
|
|
13874
|
+
* for the message.
|
|
13875
|
+
*
|
|
13876
|
+
* @param maxMb - The maximum allowed size in megabytes.
|
|
13877
|
+
* @param errorKey - Translation key returned when the file is too large.
|
|
13723
13878
|
*
|
|
13724
13879
|
* #### **Usage**
|
|
13725
13880
|
* ```ts
|
|
@@ -13737,7 +13892,15 @@ class QdValidators {
|
|
|
13737
13892
|
};
|
|
13738
13893
|
}
|
|
13739
13894
|
/**
|
|
13740
|
-
* Validates that
|
|
13895
|
+
* Validates that a selected file matches one of the accepted types.
|
|
13896
|
+
*
|
|
13897
|
+
* Each accepted entry is either a MIME type (`'application/pdf'`), a MIME wildcard
|
|
13898
|
+
* (`'image/*'`), or a file extension (`'.pdf'`); matching is case-insensitive. Non-file
|
|
13899
|
+
* values — including `null` — pass, so combine with `required` when a file is mandatory. The
|
|
13900
|
+
* error carries `params.accepted` for the message.
|
|
13901
|
+
*
|
|
13902
|
+
* @param accepted - Allowed MIME types, MIME wildcards or extensions.
|
|
13903
|
+
* @param errorKey - Translation key returned when the file type is not accepted.
|
|
13741
13904
|
*
|
|
13742
13905
|
* #### **Usage**
|
|
13743
13906
|
* ```ts
|
|
@@ -15176,7 +15339,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
15176
15339
|
args: ['class.qd-radio-buttons-error']
|
|
15177
15340
|
}] } });
|
|
15178
15341
|
|
|
15342
|
+
/**
|
|
15343
|
+
* `UntypedFormGroup` that wires cross-field re-validation automatically.
|
|
15344
|
+
*
|
|
15345
|
+
* A validator can declare a sibling dependency via `qdRevalidates` (see `QdValidators.dateRange`).
|
|
15346
|
+
* The group then subscribes to that partner's `valueChanges` and re-validates the dependent control,
|
|
15347
|
+
* so a stale error never lingers when the partner value changes — without the consumer calling
|
|
15348
|
+
* `updateValueAndValidity`. The subscriptions are group-internal (sibling to sibling) and are torn
|
|
15349
|
+
* down and rebuilt whenever a control is added, replaced or removed.
|
|
15350
|
+
*
|
|
15351
|
+
* Re-wiring is triggered by control mutations (`add`/`set`/`removeControl`), not by validator
|
|
15352
|
+
* mutations on an existing control: calling `control.addValidators(...)` after construction updates
|
|
15353
|
+
* the control's partners but does not re-wire the group until the next control mutation.
|
|
15354
|
+
*/
|
|
15179
15355
|
class QdFormGroup extends UntypedFormGroup {
|
|
15356
|
+
revalidationSubscription = new Subscription();
|
|
15357
|
+
constructor(controls, validatorOrOpts, asyncValidator) {
|
|
15358
|
+
super(controls, validatorOrOpts, asyncValidator);
|
|
15359
|
+
this.wireCrossFieldRevalidation();
|
|
15360
|
+
}
|
|
15361
|
+
addControl(name, control, options) {
|
|
15362
|
+
super.addControl(name, control, options);
|
|
15363
|
+
this.rewireCrossFieldRevalidation();
|
|
15364
|
+
}
|
|
15365
|
+
setControl(name, control, options) {
|
|
15366
|
+
super.setControl(name, control, options);
|
|
15367
|
+
this.rewireCrossFieldRevalidation();
|
|
15368
|
+
}
|
|
15369
|
+
removeControl(name, options) {
|
|
15370
|
+
super.removeControl(name, options);
|
|
15371
|
+
this.rewireCrossFieldRevalidation();
|
|
15372
|
+
}
|
|
15373
|
+
rewireCrossFieldRevalidation() {
|
|
15374
|
+
this.revalidationSubscription.unsubscribe();
|
|
15375
|
+
this.revalidationSubscription = new Subscription();
|
|
15376
|
+
this.wireCrossFieldRevalidation();
|
|
15377
|
+
}
|
|
15378
|
+
wireCrossFieldRevalidation() {
|
|
15379
|
+
Object.keys(this.controls).forEach(name => {
|
|
15380
|
+
const control = this.controls[name];
|
|
15381
|
+
if (!(control instanceof QdFormControl))
|
|
15382
|
+
return;
|
|
15383
|
+
const partnerNames = control.getRevalidationPartners();
|
|
15384
|
+
if (!partnerNames.length)
|
|
15385
|
+
return;
|
|
15386
|
+
partnerNames.forEach(partnerName => {
|
|
15387
|
+
const partner = this.get(partnerName);
|
|
15388
|
+
if (!partner)
|
|
15389
|
+
return;
|
|
15390
|
+
this.revalidationSubscription.add(partner.valueChanges.subscribe(() => control.updateValueAndValidity({ emitEvent: false })));
|
|
15391
|
+
});
|
|
15392
|
+
control.updateValueAndValidity({ emitEvent: false });
|
|
15393
|
+
});
|
|
15394
|
+
}
|
|
15180
15395
|
}
|
|
15181
15396
|
|
|
15182
15397
|
class QdFormBuilder extends UntypedFormBuilder {
|