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