@quadrel-enterprise-ui/framework 20.21.0 → 20.21.1-beta.193.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 +254 -33
- package/fesm2022/quadrel-enterprise-ui-framework.mjs.map +1 -1
- package/index.d.ts +194 -23
- 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
|
@@ -3124,14 +3124,15 @@ class QdMockCheckboxComponent {
|
|
|
3124
3124
|
value;
|
|
3125
3125
|
disabled = false;
|
|
3126
3126
|
testId = 'checkbox';
|
|
3127
|
+
valueChange = new EventEmitter();
|
|
3127
3128
|
get dataTestId() {
|
|
3128
3129
|
return this.testId;
|
|
3129
3130
|
}
|
|
3130
|
-
handleClick(
|
|
3131
|
-
|
|
3131
|
+
handleClick() {
|
|
3132
|
+
this.valueChange.emit(this.value);
|
|
3132
3133
|
}
|
|
3133
3134
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdMockCheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3134
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdMockCheckboxComponent, isStandalone: false, selector: "qd-checkbox", inputs: { inputData: "inputData", value: "value", disabled: "disabled", testId: ["data-test-id", "testId"] }, host: { properties: { "attr.data-test-id": "this.dataTestId" } }, ngImport: i0, template: 'inputData: {{inputData | json}}, value: {{value}}, disabled: {{disabled | json}}', isInline: true, dependencies: [{ kind: "pipe", type: i1.JsonPipe, name: "json" }] });
|
|
3135
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdMockCheckboxComponent, isStandalone: false, selector: "qd-checkbox", inputs: { inputData: "inputData", value: "value", disabled: "disabled", testId: ["data-test-id", "testId"] }, outputs: { valueChange: "valueChange" }, host: { listeners: { "click": "handleClick()" }, properties: { "attr.data-test-id": "this.dataTestId" } }, ngImport: i0, template: 'inputData: {{inputData | json}}, value: {{value}}, disabled: {{disabled | json}}', isInline: true, dependencies: [{ kind: "pipe", type: i1.JsonPipe, name: "json" }] });
|
|
3135
3136
|
}
|
|
3136
3137
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdMockCheckboxComponent, decorators: [{
|
|
3137
3138
|
type: Component,
|
|
@@ -3149,9 +3150,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
3149
3150
|
}], testId: [{
|
|
3150
3151
|
type: Input,
|
|
3151
3152
|
args: ['data-test-id']
|
|
3153
|
+
}], valueChange: [{
|
|
3154
|
+
type: Output
|
|
3152
3155
|
}], dataTestId: [{
|
|
3153
3156
|
type: HostBinding,
|
|
3154
3157
|
args: ['attr.data-test-id']
|
|
3158
|
+
}], handleClick: [{
|
|
3159
|
+
type: HostListener,
|
|
3160
|
+
args: ['click']
|
|
3155
3161
|
}] } });
|
|
3156
3162
|
|
|
3157
3163
|
// @ts-strict-ignore
|
|
@@ -8468,6 +8474,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
8468
8474
|
// @ts-strict-ignore
|
|
8469
8475
|
class QdFormControl extends UntypedFormControl {
|
|
8470
8476
|
maxLength;
|
|
8477
|
+
revalidationPartners = [];
|
|
8471
8478
|
validatorList;
|
|
8472
8479
|
constructor(formState, validatorOrOpts, asyncValidator) {
|
|
8473
8480
|
super(formState, validatorOrOpts, asyncValidator);
|
|
@@ -8482,12 +8489,15 @@ class QdFormControl extends UntypedFormControl {
|
|
|
8482
8489
|
}
|
|
8483
8490
|
setPropsFromValidatorList() {
|
|
8484
8491
|
let maxLength;
|
|
8492
|
+
const revalidationPartners = [];
|
|
8485
8493
|
this.validatorList.forEach((validatorFn) => {
|
|
8486
|
-
if (validatorFn.maxLength)
|
|
8494
|
+
if (validatorFn.maxLength)
|
|
8487
8495
|
maxLength = validatorFn.maxLength;
|
|
8488
|
-
|
|
8496
|
+
if (validatorFn.qdRevalidates)
|
|
8497
|
+
revalidationPartners.push(validatorFn.qdRevalidates);
|
|
8489
8498
|
});
|
|
8490
8499
|
this.maxLength = maxLength;
|
|
8500
|
+
this.revalidationPartners = revalidationPartners;
|
|
8491
8501
|
}
|
|
8492
8502
|
setValidators(validators) {
|
|
8493
8503
|
this.validatorList = this.getValidatorList(validators);
|
|
@@ -8520,6 +8530,9 @@ class QdFormControl extends UntypedFormControl {
|
|
|
8520
8530
|
getMaxLengthOrUndefined() {
|
|
8521
8531
|
return this.maxLength;
|
|
8522
8532
|
}
|
|
8533
|
+
getRevalidationPartners() {
|
|
8534
|
+
return this.revalidationPartners;
|
|
8535
|
+
}
|
|
8523
8536
|
}
|
|
8524
8537
|
function isOptionsObj$1(validatorOrOpts) {
|
|
8525
8538
|
return validatorOrOpts != null && !Array.isArray(validatorOrOpts) && typeof validatorOrOpts === 'object';
|
|
@@ -9657,7 +9670,7 @@ class QdCheckboxesComponent {
|
|
|
9657
9670
|
},
|
|
9658
9671
|
QdCheckboxesService,
|
|
9659
9672
|
QdFormsActionEmitterService
|
|
9660
|
-
], viewQueries: [{ propertyName: "checkboxes", predicate: QdCheckboxComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<qd-form-label\n [label]=\"label\"\n [readonly]=\"readonly\"\n [viewonly]=\"viewonly\"\n [control]=\"control\"\n [tooltip]=\"config?.tooltip\"\n [data-test-id]=\"testId\"\n [isDisabled]=\"isLabelDisabled\"\n></qd-form-label>\n\n<div class=\"qd-checkboxes__input-section\" *ngIf=\"!readonly && !viewonly\">\n <qd-filter-form-items\n *ngIf=\"filter\"\n (filterValueChange)=\"changeValue($event)\"\n [data-test-id]=\"testId + '-filter-form'\"\n ></qd-filter-form-items>\n\n <div class=\"qd-checkboxes__checkbox-section\">\n <qd-checkbox\n *ngFor=\"let checkbox of checkboxesListForView\"\n [inputData]=\"checkbox\"\n [
|
|
9673
|
+
], viewQueries: [{ propertyName: "checkboxes", predicate: QdCheckboxComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<qd-form-label\n [label]=\"label\"\n [readonly]=\"readonly\"\n [viewonly]=\"viewonly\"\n [control]=\"control\"\n [tooltip]=\"config?.tooltip\"\n [data-test-id]=\"testId\"\n [isDisabled]=\"isLabelDisabled\"\n></qd-form-label>\n\n<div class=\"qd-checkboxes__input-section\" *ngIf=\"!readonly && !viewonly\">\n <qd-filter-form-items\n *ngIf=\"filter\"\n (filterValueChange)=\"changeValue($event)\"\n [data-test-id]=\"testId + '-filter-form'\"\n ></qd-filter-form-items>\n\n <div class=\"qd-checkboxes__checkbox-section\">\n <qd-checkbox\n *ngFor=\"let checkbox of checkboxesListForView\"\n [inputData]=\"checkbox\"\n [value]=\"checkboxesValues[checkbox.index]\"\n [disabled]=\"checkbox.disabled || disabled\"\n (valueChange)=\"handleClick(checkbox)\"\n [data-test-id]=\"testId + '-checkbox-' + checkbox.index\"\n ></qd-checkbox>\n </div>\n</div>\n\n<qd-form-hint\n *ngIf=\"!readonly && !viewonly && (hint || hasError)\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n></qd-form-hint>\n\n<qd-form-readonly\n *ngIf=\"readonly\"\n [values]=\"selectedValuesTranslated\"\n [readonlyAction]=\"readonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-readonly>\n\n<qd-form-viewonly\n *ngIf=\"viewonly\"\n [values]=\"selectedValuesTranslated\"\n [viewonlyAction]=\"viewonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-viewonly>\n", styles: [".qd-checkboxes{display:block;margin-bottom:.75rem}@media (max-width: 959.98px){.qd-checkboxes{height:initial}}.qd-checkboxes .qd-checkboxes__input-section{display:block;flex-direction:column;margin-bottom:.3125rem}.qd-checkboxes .qd-checkboxes__checkbox-section{display:flex;min-height:2.25rem;flex-direction:row}@media (max-width: 959.98px){.qd-checkboxes .qd-checkboxes__checkbox-section{height:initial;flex-direction:column}}.qd-checkboxes.qd-checkboxes-vertical .qd-checkboxes__checkbox-section{display:flex;flex-direction:column}.qd-checkboxes.qd-checkboxes-vertical .qd-checkboxes__checkbox-section .qd-checkbox:not(:last-child){margin-bottom:.5rem}.qd-checkboxes.qd-checkboxes-disabled{pointer-events:none}.qd-checkboxes-readonly .qd-checkboxes__input-section{font-size:.875rem;line-height:2.25rem}.qd-checkboxes--readonly-action .qd-checkboxes__input-section{color:#069;cursor:pointer}.qd-checkboxes--readonly-action .qd-checkboxes__input-section:hover,.qd-checkboxes--readonly-action .qd-checkboxes__input-section:active,.qd-checkboxes--readonly-action .qd-checkboxes__input-section:focus{text-decoration:underline}.qd-checkboxes-viewonly .qd-checkboxes__input-section{font-size:.875rem;line-height:2.25rem}.qd-checkboxes--viewonly-action .qd-checkboxes__input-section{color:#069;cursor:pointer}.qd-checkboxes--viewonly-action .qd-checkboxes__input-section:hover,.qd-checkboxes--viewonly-action .qd-checkboxes__input-section:active,.qd-checkboxes--viewonly-action .qd-checkboxes__input-section:focus{text-decoration:underline}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: QdCheckboxComponent, selector: "qd-checkbox", inputs: ["inputData", "value", "data-test-id", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: QdFilterFormItemsComponent, selector: "qd-filter-form-items", inputs: ["inputFilterValue", "data-test-id"], outputs: ["filterValueChange"] }, { kind: "component", type: QdFormHintComponent, selector: "qd-form-hint", inputs: ["hint", "control", "hasError", "hintAction", "data-test-id"] }, { kind: "component", type: QdFormLabelComponent, selector: "qd-form-label", inputs: ["label", "isDisabled", "readonly", "viewonly", "control", "tooltip", "data-test-id"] }, { kind: "component", type: QdFormReadonlyComponent, selector: "qd-form-readonly", inputs: ["values", "readonlyAction", "data-test-id"] }, { kind: "component", type: QdFormViewonlyComponent, selector: "qd-form-viewonly", inputs: ["values", "viewonlyAction", "data-test-id"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
9661
9674
|
}
|
|
9662
9675
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdCheckboxesComponent, decorators: [{
|
|
9663
9676
|
type: Component,
|
|
@@ -9669,7 +9682,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
9669
9682
|
},
|
|
9670
9683
|
QdCheckboxesService,
|
|
9671
9684
|
QdFormsActionEmitterService
|
|
9672
|
-
], encapsulation: ViewEncapsulation.None, host: { class: 'qd-checkboxes' }, standalone: false, template: "<qd-form-label\n [label]=\"label\"\n [readonly]=\"readonly\"\n [viewonly]=\"viewonly\"\n [control]=\"control\"\n [tooltip]=\"config?.tooltip\"\n [data-test-id]=\"testId\"\n [isDisabled]=\"isLabelDisabled\"\n></qd-form-label>\n\n<div class=\"qd-checkboxes__input-section\" *ngIf=\"!readonly && !viewonly\">\n <qd-filter-form-items\n *ngIf=\"filter\"\n (filterValueChange)=\"changeValue($event)\"\n [data-test-id]=\"testId + '-filter-form'\"\n ></qd-filter-form-items>\n\n <div class=\"qd-checkboxes__checkbox-section\">\n <qd-checkbox\n *ngFor=\"let checkbox of checkboxesListForView\"\n [inputData]=\"checkbox\"\n [
|
|
9685
|
+
], encapsulation: ViewEncapsulation.None, host: { class: 'qd-checkboxes' }, standalone: false, template: "<qd-form-label\n [label]=\"label\"\n [readonly]=\"readonly\"\n [viewonly]=\"viewonly\"\n [control]=\"control\"\n [tooltip]=\"config?.tooltip\"\n [data-test-id]=\"testId\"\n [isDisabled]=\"isLabelDisabled\"\n></qd-form-label>\n\n<div class=\"qd-checkboxes__input-section\" *ngIf=\"!readonly && !viewonly\">\n <qd-filter-form-items\n *ngIf=\"filter\"\n (filterValueChange)=\"changeValue($event)\"\n [data-test-id]=\"testId + '-filter-form'\"\n ></qd-filter-form-items>\n\n <div class=\"qd-checkboxes__checkbox-section\">\n <qd-checkbox\n *ngFor=\"let checkbox of checkboxesListForView\"\n [inputData]=\"checkbox\"\n [value]=\"checkboxesValues[checkbox.index]\"\n [disabled]=\"checkbox.disabled || disabled\"\n (valueChange)=\"handleClick(checkbox)\"\n [data-test-id]=\"testId + '-checkbox-' + checkbox.index\"\n ></qd-checkbox>\n </div>\n</div>\n\n<qd-form-hint\n *ngIf=\"!readonly && !viewonly && (hint || hasError)\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n></qd-form-hint>\n\n<qd-form-readonly\n *ngIf=\"readonly\"\n [values]=\"selectedValuesTranslated\"\n [readonlyAction]=\"readonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-readonly>\n\n<qd-form-viewonly\n *ngIf=\"viewonly\"\n [values]=\"selectedValuesTranslated\"\n [viewonlyAction]=\"viewonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-viewonly>\n", styles: [".qd-checkboxes{display:block;margin-bottom:.75rem}@media (max-width: 959.98px){.qd-checkboxes{height:initial}}.qd-checkboxes .qd-checkboxes__input-section{display:block;flex-direction:column;margin-bottom:.3125rem}.qd-checkboxes .qd-checkboxes__checkbox-section{display:flex;min-height:2.25rem;flex-direction:row}@media (max-width: 959.98px){.qd-checkboxes .qd-checkboxes__checkbox-section{height:initial;flex-direction:column}}.qd-checkboxes.qd-checkboxes-vertical .qd-checkboxes__checkbox-section{display:flex;flex-direction:column}.qd-checkboxes.qd-checkboxes-vertical .qd-checkboxes__checkbox-section .qd-checkbox:not(:last-child){margin-bottom:.5rem}.qd-checkboxes.qd-checkboxes-disabled{pointer-events:none}.qd-checkboxes-readonly .qd-checkboxes__input-section{font-size:.875rem;line-height:2.25rem}.qd-checkboxes--readonly-action .qd-checkboxes__input-section{color:#069;cursor:pointer}.qd-checkboxes--readonly-action .qd-checkboxes__input-section:hover,.qd-checkboxes--readonly-action .qd-checkboxes__input-section:active,.qd-checkboxes--readonly-action .qd-checkboxes__input-section:focus{text-decoration:underline}.qd-checkboxes-viewonly .qd-checkboxes__input-section{font-size:.875rem;line-height:2.25rem}.qd-checkboxes--viewonly-action .qd-checkboxes__input-section{color:#069;cursor:pointer}.qd-checkboxes--viewonly-action .qd-checkboxes__input-section:hover,.qd-checkboxes--viewonly-action .qd-checkboxes__input-section:active,.qd-checkboxes--viewonly-action .qd-checkboxes__input-section:focus{text-decoration:underline}\n"] }]
|
|
9673
9686
|
}], ctorParameters: () => [], propDecorators: { formControlName: [{
|
|
9674
9687
|
type: Input
|
|
9675
9688
|
}], values: [{
|
|
@@ -12387,6 +12400,8 @@ class QdDatepickerComponent {
|
|
|
12387
12400
|
const current = this.config?.disabledDates;
|
|
12388
12401
|
if (current === this._boundDisabledDates)
|
|
12389
12402
|
return;
|
|
12403
|
+
if (!this.control)
|
|
12404
|
+
return;
|
|
12390
12405
|
this._boundDisabledDates = current;
|
|
12391
12406
|
this.validateDisabledDates();
|
|
12392
12407
|
}
|
|
@@ -12394,6 +12409,8 @@ class QdDatepickerComponent {
|
|
|
12394
12409
|
const current = this.config?.timePicker?.disabledTimes;
|
|
12395
12410
|
if (current === this._boundDisabledTimes)
|
|
12396
12411
|
return;
|
|
12412
|
+
if (!this.control)
|
|
12413
|
+
return;
|
|
12397
12414
|
this._boundDisabledTimes = current;
|
|
12398
12415
|
this.validateDisabledTimes();
|
|
12399
12416
|
}
|
|
@@ -13524,14 +13541,40 @@ const validatorsDroppedWithOptsWarning = 'Quadrel Framework | QdForms - QdFormCo
|
|
|
13524
13541
|
function hasUnit(control) {
|
|
13525
13542
|
return control.value?.value != null && control.value?.unit != null;
|
|
13526
13543
|
}
|
|
13544
|
+
/**
|
|
13545
|
+
* Ready-to-use validators for Quadrel Reactive Forms.
|
|
13546
|
+
*
|
|
13547
|
+
* Use them like Angular's built-in `Validators`, but every validator returns a **translatable
|
|
13548
|
+
* error key** instead of a fixed message, and most accept a custom `errorKey` as the last
|
|
13549
|
+
* argument.
|
|
13550
|
+
*
|
|
13551
|
+
* Empty values pass for most validators — combine with `required()` when a value is mandatory.
|
|
13552
|
+
* The amount-aware validators (`min`, `max`, `minLength`, `maxLength`, `pattern`) also accept
|
|
13553
|
+
* `{ value, unit }` objects and validate the inner `value`.
|
|
13554
|
+
*
|
|
13555
|
+
* #### **Usage**
|
|
13556
|
+
* ```ts
|
|
13557
|
+
* form = new QdFormGroup({
|
|
13558
|
+
* email: new QdFormControl(null, [QdValidators.required(), QdValidators.email()]),
|
|
13559
|
+
* age: new QdFormControl(null, [QdValidators.required(), QdValidators.min(18)])
|
|
13560
|
+
* });
|
|
13561
|
+
* ```
|
|
13562
|
+
*/
|
|
13527
13563
|
class QdValidators {
|
|
13528
13564
|
/**
|
|
13529
|
-
* Validates that
|
|
13565
|
+
* Validates that a numeric value is greater than or equal to a minimum.
|
|
13566
|
+
*
|
|
13567
|
+
* Empty values (`null`/`undefined`) pass — combine with `required` when a value is mandatory.
|
|
13568
|
+
* Also accepts amount objects of the shape `{ value, unit }`; in that case the inner `value`
|
|
13569
|
+
* is validated.
|
|
13570
|
+
*
|
|
13571
|
+
* @param min - The smallest allowed value (inclusive).
|
|
13572
|
+
* @param errorKey - Translation key returned when the value is below the minimum.
|
|
13530
13573
|
*
|
|
13531
13574
|
* #### **Usage**
|
|
13532
13575
|
* ```ts
|
|
13533
|
-
* new QdFormControl(
|
|
13534
|
-
* new QdFormControl(
|
|
13576
|
+
* new QdFormControl(null, QdValidators.min(3));
|
|
13577
|
+
* new QdFormControl(null, QdValidators.min(3, 'custom-error'));
|
|
13535
13578
|
* ```
|
|
13536
13579
|
*/
|
|
13537
13580
|
static min(min, errorKey = 'i18n.qd.form.error.min') {
|
|
@@ -13543,12 +13586,19 @@ class QdValidators {
|
|
|
13543
13586
|
return validFn;
|
|
13544
13587
|
}
|
|
13545
13588
|
/**
|
|
13546
|
-
* Validates that
|
|
13589
|
+
* Validates that a numeric value is less than or equal to a maximum.
|
|
13590
|
+
*
|
|
13591
|
+
* Empty values (`null`/`undefined`) pass — combine with `required` when a value is mandatory.
|
|
13592
|
+
* Also accepts amount objects of the shape `{ value, unit }`; in that case the inner `value`
|
|
13593
|
+
* is validated.
|
|
13594
|
+
*
|
|
13595
|
+
* @param max - The largest allowed value (inclusive).
|
|
13596
|
+
* @param errorKey - Translation key returned when the value exceeds the maximum.
|
|
13547
13597
|
*
|
|
13548
13598
|
* #### **Usage**
|
|
13549
13599
|
* ```ts
|
|
13550
|
-
* new QdFormControl(
|
|
13551
|
-
* new QdFormControl(
|
|
13600
|
+
* new QdFormControl(null, QdValidators.max(10));
|
|
13601
|
+
* new QdFormControl(null, QdValidators.max(10, 'custom-error'));
|
|
13552
13602
|
* ```
|
|
13553
13603
|
*/
|
|
13554
13604
|
static max(max, errorKey = 'i18n.qd.form.error.max') {
|
|
@@ -13560,7 +13610,16 @@ class QdValidators {
|
|
|
13560
13610
|
return validFn;
|
|
13561
13611
|
}
|
|
13562
13612
|
/**
|
|
13563
|
-
*
|
|
13613
|
+
* Validates that the field holds a non-empty value.
|
|
13614
|
+
*
|
|
13615
|
+
* Quadrel form components additionally render a required asterisk (`*`) on the field label
|
|
13616
|
+
* whenever this validator is present, so users see at a glance that the field is mandatory.
|
|
13617
|
+
*
|
|
13618
|
+
* Empty means: `null`, `undefined`, an empty string, an empty array, or an object whose
|
|
13619
|
+
* leaf values are all empty (checked recursively — useful for amount objects such as
|
|
13620
|
+
* `{ value, unit }`).
|
|
13621
|
+
*
|
|
13622
|
+
* @param errorKey - Translation key returned when the field is empty.
|
|
13564
13623
|
*
|
|
13565
13624
|
* #### **Usage**
|
|
13566
13625
|
* ```ts
|
|
@@ -13583,7 +13642,12 @@ class QdValidators {
|
|
|
13583
13642
|
return value == null || (typeof value === 'string' && value.length === 0);
|
|
13584
13643
|
}
|
|
13585
13644
|
/**
|
|
13586
|
-
* Validates that the
|
|
13645
|
+
* Validates that the field contains a single, well-formed email address.
|
|
13646
|
+
*
|
|
13647
|
+
* Empty values pass — combine with `required` when an address is mandatory. The whole value
|
|
13648
|
+
* must be the address; surrounding text makes it invalid.
|
|
13649
|
+
*
|
|
13650
|
+
* @param errorKey - Translation key returned when the address is malformed.
|
|
13587
13651
|
*
|
|
13588
13652
|
* #### **Usage**
|
|
13589
13653
|
* ```ts
|
|
@@ -13598,7 +13662,14 @@ class QdValidators {
|
|
|
13598
13662
|
return validFn;
|
|
13599
13663
|
}
|
|
13600
13664
|
/**
|
|
13601
|
-
*
|
|
13665
|
+
* Validates that a text value is at least a given number of characters long.
|
|
13666
|
+
*
|
|
13667
|
+
* Empty values (`null`/`undefined`/`''`) pass — combine with `required` when input is
|
|
13668
|
+
* mandatory. Also accepts amount objects of the shape `{ value, unit }`; in that case the
|
|
13669
|
+
* inner `value` is measured.
|
|
13670
|
+
*
|
|
13671
|
+
* @param minLength - The minimum number of characters (inclusive).
|
|
13672
|
+
* @param errorKey - Translation key returned when the value is too short.
|
|
13602
13673
|
*
|
|
13603
13674
|
* #### **Usage**
|
|
13604
13675
|
* ```ts
|
|
@@ -13615,7 +13686,15 @@ class QdValidators {
|
|
|
13615
13686
|
return validFn;
|
|
13616
13687
|
}
|
|
13617
13688
|
/**
|
|
13618
|
-
*
|
|
13689
|
+
* Validates that a text value is no longer than a given number of characters.
|
|
13690
|
+
*
|
|
13691
|
+
* Empty values pass — combine with `required` when input is mandatory. Also accepts amount
|
|
13692
|
+
* objects of the shape `{ value, unit }`; in that case the inner `value` is measured. The
|
|
13693
|
+
* configured limit is exposed as `.maxLength` on the returned validator, which `qd-textarea`
|
|
13694
|
+
* reads to show a live character counter (`current / max`).
|
|
13695
|
+
*
|
|
13696
|
+
* @param maxLength - The maximum number of characters (inclusive).
|
|
13697
|
+
* @param errorKey - Translation key returned when the value is too long.
|
|
13619
13698
|
*
|
|
13620
13699
|
* #### **Usage**
|
|
13621
13700
|
* ```ts
|
|
@@ -13633,7 +13712,13 @@ class QdValidators {
|
|
|
13633
13712
|
return validFn;
|
|
13634
13713
|
}
|
|
13635
13714
|
/**
|
|
13636
|
-
*
|
|
13715
|
+
* Validates that a text value matches a regular expression.
|
|
13716
|
+
*
|
|
13717
|
+
* Empty values pass — combine with `required` when input is mandatory. Also accepts amount
|
|
13718
|
+
* objects of the shape `{ value, unit }`; in that case the inner `value` is matched.
|
|
13719
|
+
*
|
|
13720
|
+
* @param pattern - The pattern to match, as a `RegExp` or a string regular expression.
|
|
13721
|
+
* @param errorKey - Translation key returned when the value does not match.
|
|
13637
13722
|
*
|
|
13638
13723
|
* #### **Usage**
|
|
13639
13724
|
* ```ts
|
|
@@ -13651,11 +13736,17 @@ class QdValidators {
|
|
|
13651
13736
|
return validFn;
|
|
13652
13737
|
}
|
|
13653
13738
|
/**
|
|
13654
|
-
*
|
|
13739
|
+
* Validates that the value is a real, parseable `Date` object.
|
|
13740
|
+
*
|
|
13741
|
+
* Empty values pass — combine with `required` when a date is mandatory. Strings (including
|
|
13742
|
+
* `'Invalid Date'`), numbers and plain objects are rejected. The error carries the locale
|
|
13743
|
+
* date format (`DD.MM.YYYY`) as a `params.format` hint for the message.
|
|
13744
|
+
*
|
|
13745
|
+
* @param errorKey - Translation key returned when the value is not a valid date.
|
|
13655
13746
|
*
|
|
13656
13747
|
* #### **Usage**
|
|
13657
13748
|
* ```ts
|
|
13658
|
-
* new QdFormControl(
|
|
13749
|
+
* new QdFormControl(null, QdValidators.date());
|
|
13659
13750
|
* new QdFormControl(new Date(), QdValidators.date());
|
|
13660
13751
|
* new QdFormControl(new Date(), QdValidators.date('date-error'));
|
|
13661
13752
|
* ```
|
|
@@ -13666,24 +13757,29 @@ class QdValidators {
|
|
|
13666
13757
|
return null;
|
|
13667
13758
|
const localizedFormat = moment().format('DD.MM.YYYY');
|
|
13668
13759
|
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;
|
|
13760
|
+
return this.isValidDate(value) ? null : formattedErrorKey;
|
|
13674
13761
|
};
|
|
13675
13762
|
}
|
|
13676
13763
|
/**
|
|
13677
|
-
*
|
|
13764
|
+
* Validates that a date does not fall inside any of the given disabled ranges.
|
|
13765
|
+
*
|
|
13766
|
+
* Each range may set `from`, `to`, or both; an open end reaches into the far past/future.
|
|
13767
|
+
* Boundaries are **exclusive** — a date exactly on `from` or `to` is still allowed; only
|
|
13768
|
+
* dates strictly between them are rejected. Comparison is day-granular. Empty or invalid
|
|
13769
|
+
* values pass.
|
|
13770
|
+
*
|
|
13771
|
+
* @param disabledDates - Ranges to block, e.g. `[{ from, to }]`.
|
|
13772
|
+
* @param errorKey - Translation key returned when the date lies inside a range.
|
|
13678
13773
|
*
|
|
13679
13774
|
* #### **Usage**
|
|
13680
13775
|
* ```ts
|
|
13681
|
-
* new QdFormControl(
|
|
13776
|
+
* new QdFormControl(null, QdValidators.disabledDates([{ from: new Date('2025-01-01') }]));
|
|
13777
|
+
* new QdFormControl(null, QdValidators.disabledDates([{ from: new Date('2025-01-01'), to: new Date('2025-01-31') }]));
|
|
13682
13778
|
* ```
|
|
13683
13779
|
*/
|
|
13684
13780
|
static disabledDates(disabledDates, errorKey = 'i18n.qd.form.error.disabledDates') {
|
|
13685
13781
|
const validFn = (control) => {
|
|
13686
|
-
if (!
|
|
13782
|
+
if (!this.isValidDate(control.value))
|
|
13687
13783
|
return null;
|
|
13688
13784
|
const date = moment(control.value.getTime());
|
|
13689
13785
|
return this.isDateDisabled(disabledDates, date) ? { disabledDates: errorKey } : null;
|
|
@@ -13702,16 +13798,74 @@ class QdValidators {
|
|
|
13702
13798
|
});
|
|
13703
13799
|
}
|
|
13704
13800
|
/**
|
|
13705
|
-
*
|
|
13801
|
+
* Validates that a date stays on the correct side of a sibling "range partner" control.
|
|
13802
|
+
*
|
|
13803
|
+
* Put it on both ends of a from/to pair, each pointing at the other. A `'start'` control is
|
|
13804
|
+
* invalid when its date is after the partner; an `'end'` control is invalid when its date is
|
|
13805
|
+
* before the partner. Comparison is day-granular, so equal days are valid.
|
|
13806
|
+
*
|
|
13807
|
+
* The partner value is read live on every run, so the limit is never cached — it stays
|
|
13808
|
+
* correct across form rebuilds, saves and config changes. Empty or invalid own/partner
|
|
13809
|
+
* values, and a missing partner control, all pass.
|
|
13810
|
+
*
|
|
13811
|
+
* Inside a `QdFormGroup` the partner is re-validated automatically when this control changes
|
|
13812
|
+
* (and vice versa), so a stale error never lingers — no manual `updateValueAndValidity` needed.
|
|
13813
|
+
* The validator declares this dependency via `qdRevalidates`, which the group reads.
|
|
13814
|
+
*
|
|
13815
|
+
* The auto-revalidation only applies when both controls are `QdFormControl`s inside a
|
|
13816
|
+
* `QdFormGroup`, and only for validators present at construction or set via the group's
|
|
13817
|
+
* `add`/`set`/`removeControl`. On a native `FormGroup`/`FormControl`, or when the validator is
|
|
13818
|
+
* added later via `control.addValidators(...)`, re-validate the partner manually with
|
|
13819
|
+
* `partner.updateValueAndValidity({ emitEvent: false })` whenever this control changes.
|
|
13820
|
+
*
|
|
13821
|
+
* @param partnerControlName - Name of the sibling control holding the other end of the range.
|
|
13822
|
+
* @param position - `'start'` for the from-control, `'end'` for the to-control.
|
|
13823
|
+
* @param errorKey - Translation key returned when the order is violated.
|
|
13706
13824
|
*
|
|
13707
13825
|
* #### **Usage**
|
|
13708
13826
|
* ```ts
|
|
13709
|
-
* new
|
|
13827
|
+
* new QdFormGroup({
|
|
13828
|
+
* from: new QdFormControl(null, QdValidators.dateRange('to', 'start')),
|
|
13829
|
+
* to: new QdFormControl(null, QdValidators.dateRange('from', 'end'))
|
|
13830
|
+
* });
|
|
13831
|
+
* ```
|
|
13832
|
+
*/
|
|
13833
|
+
static dateRange(partnerControlName, position, errorKey = 'i18n.qd.form.error.dateRange') {
|
|
13834
|
+
const validFn = (control) => {
|
|
13835
|
+
const ownValue = control.value;
|
|
13836
|
+
const partnerValue = control.parent?.get(partnerControlName)?.value;
|
|
13837
|
+
if (!this.isValidDate(ownValue) || !this.isValidDate(partnerValue))
|
|
13838
|
+
return null;
|
|
13839
|
+
const own = moment(ownValue);
|
|
13840
|
+
const partner = moment(partnerValue);
|
|
13841
|
+
const isInvalid = position === 'start' ? own.isAfter(partner, 'day') : own.isBefore(partner, 'day');
|
|
13842
|
+
return isInvalid ? { dateRange: errorKey } : null;
|
|
13843
|
+
};
|
|
13844
|
+
validFn.qdRevalidates = partnerControlName;
|
|
13845
|
+
return validFn;
|
|
13846
|
+
}
|
|
13847
|
+
static isValidDate(value) {
|
|
13848
|
+
return value instanceof Date && !isNaN(value.getTime());
|
|
13849
|
+
}
|
|
13850
|
+
/**
|
|
13851
|
+
* Validates that the time of a date value does not fall inside any disabled time range.
|
|
13852
|
+
*
|
|
13853
|
+
* Each range may set `from`, `to`, or both, as `HH:mm` strings. Boundaries are **exclusive** —
|
|
13854
|
+
* a time exactly on `from` or `to` is allowed; only times strictly between them are rejected.
|
|
13855
|
+
* Only the time-of-day is considered, not the date. Empty or invalid values pass.
|
|
13856
|
+
*
|
|
13857
|
+
* @param disabledTimes - Ranges to block, e.g. `[{ from: '12:00', to: '13:00' }]`.
|
|
13858
|
+
* @param errorKey - Translation key returned when the time lies inside a range.
|
|
13859
|
+
*
|
|
13860
|
+
* #### **Usage**
|
|
13861
|
+
* ```ts
|
|
13862
|
+
* new QdFormControl(null, QdValidators.disabledTimes([{ from: '15:00' }]));
|
|
13863
|
+
* new QdFormControl(null, QdValidators.disabledTimes([{ from: '12:00', to: '13:00' }]));
|
|
13710
13864
|
* ```
|
|
13711
13865
|
*/
|
|
13712
13866
|
static disabledTimes(disabledTimes, errorKey = 'i18n.qd.form.error.disabledTimes') {
|
|
13713
13867
|
const validFn = (control) => {
|
|
13714
|
-
if (!
|
|
13868
|
+
if (!this.isValidDate(control.value))
|
|
13715
13869
|
return null;
|
|
13716
13870
|
const time = moment(control.value).format('HH:mm');
|
|
13717
13871
|
return TimePickerService.isTimeDisabled(time, disabledTimes) ? { disabledTimes: errorKey } : null;
|
|
@@ -13719,7 +13873,14 @@ class QdValidators {
|
|
|
13719
13873
|
return validFn;
|
|
13720
13874
|
}
|
|
13721
13875
|
/**
|
|
13722
|
-
*
|
|
13876
|
+
* Validates that a selected file does not exceed a maximum size.
|
|
13877
|
+
*
|
|
13878
|
+
* Operates on a `File` value (e.g. from a file input). Non-file values — including `null` —
|
|
13879
|
+
* pass, so combine with `required` when a file is mandatory. The error carries `params.maxMb`
|
|
13880
|
+
* for the message.
|
|
13881
|
+
*
|
|
13882
|
+
* @param maxMb - The maximum allowed size in megabytes.
|
|
13883
|
+
* @param errorKey - Translation key returned when the file is too large.
|
|
13723
13884
|
*
|
|
13724
13885
|
* #### **Usage**
|
|
13725
13886
|
* ```ts
|
|
@@ -13737,7 +13898,15 @@ class QdValidators {
|
|
|
13737
13898
|
};
|
|
13738
13899
|
}
|
|
13739
13900
|
/**
|
|
13740
|
-
* Validates that
|
|
13901
|
+
* Validates that a selected file matches one of the accepted types.
|
|
13902
|
+
*
|
|
13903
|
+
* Each accepted entry is either a MIME type (`'application/pdf'`), a MIME wildcard
|
|
13904
|
+
* (`'image/*'`), or a file extension (`'.pdf'`); matching is case-insensitive. Non-file
|
|
13905
|
+
* values — including `null` — pass, so combine with `required` when a file is mandatory. The
|
|
13906
|
+
* error carries `params.accepted` for the message.
|
|
13907
|
+
*
|
|
13908
|
+
* @param accepted - Allowed MIME types, MIME wildcards or extensions.
|
|
13909
|
+
* @param errorKey - Translation key returned when the file type is not accepted.
|
|
13741
13910
|
*
|
|
13742
13911
|
* #### **Usage**
|
|
13743
13912
|
* ```ts
|
|
@@ -15176,7 +15345,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
15176
15345
|
args: ['class.qd-radio-buttons-error']
|
|
15177
15346
|
}] } });
|
|
15178
15347
|
|
|
15348
|
+
/**
|
|
15349
|
+
* `UntypedFormGroup` that wires cross-field re-validation automatically.
|
|
15350
|
+
*
|
|
15351
|
+
* A validator can declare a sibling dependency via `qdRevalidates` (see `QdValidators.dateRange`).
|
|
15352
|
+
* The group then subscribes to that partner's `valueChanges` and re-validates the dependent control,
|
|
15353
|
+
* so a stale error never lingers when the partner value changes — without the consumer calling
|
|
15354
|
+
* `updateValueAndValidity`. The subscriptions are group-internal (sibling to sibling) and are torn
|
|
15355
|
+
* down and rebuilt whenever a control is added, replaced or removed.
|
|
15356
|
+
*
|
|
15357
|
+
* Re-wiring is triggered by control mutations (`add`/`set`/`removeControl`), not by validator
|
|
15358
|
+
* mutations on an existing control: calling `control.addValidators(...)` after construction updates
|
|
15359
|
+
* the control's partners but does not re-wire the group until the next control mutation.
|
|
15360
|
+
*/
|
|
15179
15361
|
class QdFormGroup extends UntypedFormGroup {
|
|
15362
|
+
revalidationSubscription = new Subscription();
|
|
15363
|
+
constructor(controls, validatorOrOpts, asyncValidator) {
|
|
15364
|
+
super(controls, validatorOrOpts, asyncValidator);
|
|
15365
|
+
this.wireCrossFieldRevalidation();
|
|
15366
|
+
}
|
|
15367
|
+
addControl(name, control, options) {
|
|
15368
|
+
super.addControl(name, control, options);
|
|
15369
|
+
this.rewireCrossFieldRevalidation();
|
|
15370
|
+
}
|
|
15371
|
+
setControl(name, control, options) {
|
|
15372
|
+
super.setControl(name, control, options);
|
|
15373
|
+
this.rewireCrossFieldRevalidation();
|
|
15374
|
+
}
|
|
15375
|
+
removeControl(name, options) {
|
|
15376
|
+
super.removeControl(name, options);
|
|
15377
|
+
this.rewireCrossFieldRevalidation();
|
|
15378
|
+
}
|
|
15379
|
+
rewireCrossFieldRevalidation() {
|
|
15380
|
+
this.revalidationSubscription.unsubscribe();
|
|
15381
|
+
this.revalidationSubscription = new Subscription();
|
|
15382
|
+
this.wireCrossFieldRevalidation();
|
|
15383
|
+
}
|
|
15384
|
+
wireCrossFieldRevalidation() {
|
|
15385
|
+
Object.keys(this.controls).forEach(name => {
|
|
15386
|
+
const control = this.controls[name];
|
|
15387
|
+
if (!(control instanceof QdFormControl))
|
|
15388
|
+
return;
|
|
15389
|
+
const partnerNames = control.getRevalidationPartners();
|
|
15390
|
+
if (!partnerNames.length)
|
|
15391
|
+
return;
|
|
15392
|
+
partnerNames.forEach(partnerName => {
|
|
15393
|
+
const partner = this.get(partnerName);
|
|
15394
|
+
if (!partner)
|
|
15395
|
+
return;
|
|
15396
|
+
this.revalidationSubscription.add(partner.valueChanges.subscribe(() => control.updateValueAndValidity({ emitEvent: false })));
|
|
15397
|
+
});
|
|
15398
|
+
control.updateValueAndValidity({ emitEvent: false });
|
|
15399
|
+
});
|
|
15400
|
+
}
|
|
15180
15401
|
}
|
|
15181
15402
|
|
|
15182
15403
|
class QdFormBuilder extends UntypedFormBuilder {
|