@energycap/components 0.39.20 → 0.39.21-ECAP-25650-file-upload-validation-support.20240805-1645
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/esm2020/lib/controls/file-upload/file-upload.component.mjs +38 -26
- package/esm2020/lib/core/validation-message.service.mjs +4 -1
- package/esm2020/lib/shared/page/page-base/page-base.component.mjs +7 -3
- package/fesm2015/energycap-components.mjs +44 -24
- package/fesm2015/energycap-components.mjs.map +1 -1
- package/fesm2020/energycap-components.mjs +43 -24
- package/fesm2020/energycap-components.mjs.map +1 -1
- package/lib/controls/file-upload/file-upload.component.d.ts +15 -4
- package/lib/shared/page/page-base/page-base.component.d.ts +2 -2
- package/package.json +1 -1
- package/src/assets/locales/en_US.json +2 -1
@@ -7,7 +7,7 @@ import { DOCUMENT, CommonModule } from '@angular/common';
|
|
7
7
|
import * as i0 from '@angular/core';
|
8
8
|
import { Injectable, EventEmitter, Component, HostBinding, Input, Output, ViewChild, Directive, Host, Pipe, HostListener, Inject, ElementRef, ViewEncapsulation, ContentChild, TemplateRef, ViewContainerRef, ContentChildren, NgModule, Injector } from '@angular/core';
|
9
9
|
import * as i4 from '@angular/forms';
|
10
|
-
import { Validators, UntypedFormControl, FormControlDirective, UntypedFormGroup, UntypedFormArray, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
10
|
+
import { Validators, UntypedFormControl, FormControlDirective, UntypedFormGroup, UntypedFormArray, FormGroup, FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
11
11
|
import * as i1$2 from '@angular/router';
|
12
12
|
import { NavigationEnd, convertToParamMap, NavigationStart, Router, RouterModule, ActivatedRoute } from '@angular/router';
|
13
13
|
import * as i2 from '@ngx-translate/core';
|
@@ -734,6 +734,9 @@ class ValidationMessageService {
|
|
734
734
|
case 'domain':
|
735
735
|
translationObservables.push(this.translate.get('DomainValidationMessage_SC'));
|
736
736
|
break;
|
737
|
+
case 'invalidFile':
|
738
|
+
translationObservables.push(this.translate.get('is invalid'));
|
739
|
+
break;
|
737
740
|
default:
|
738
741
|
break;
|
739
742
|
}
|
@@ -4103,18 +4106,28 @@ const FileTypeExtensions = {
|
|
4103
4106
|
};
|
4104
4107
|
class FileUploadComponent extends FormControlBase {
|
4105
4108
|
// static class to create the form group from a parent component
|
4106
|
-
static getFormModel(validators, disabled = false) {
|
4107
|
-
let formGroup = new
|
4108
|
-
file: new
|
4109
|
-
name: new
|
4110
|
-
base64FileString: new
|
4111
|
-
uploadResult: new
|
4109
|
+
static getFormModel(validators, disabled = false, fileValidators) {
|
4110
|
+
let formGroup = new FormGroup({
|
4111
|
+
file: new FormControl({ value: null, disabled: disabled }, validators),
|
4112
|
+
name: new FormControl({ value: null, disabled: disabled }, { validators: validators, asyncValidators: fileValidators }),
|
4113
|
+
base64FileString: new FormControl(null),
|
4114
|
+
uploadResult: new FormControl(null),
|
4112
4115
|
});
|
4113
4116
|
if (disabled) {
|
4114
4117
|
formGroup.disable();
|
4115
4118
|
}
|
4116
4119
|
return formGroup;
|
4117
4120
|
}
|
4121
|
+
static getFileValidator(callback) {
|
4122
|
+
return async (nameControl) => {
|
4123
|
+
if (nameControl.value && nameControl.parent && nameControl.parent.get('file')?.value) {
|
4124
|
+
let file = nameControl.parent.get('file')?.value;
|
4125
|
+
let base64 = nameControl.parent.get('base64FileString')?.value;
|
4126
|
+
return await callback(file, base64);
|
4127
|
+
}
|
4128
|
+
return null;
|
4129
|
+
};
|
4130
|
+
}
|
4118
4131
|
constructor(validationMessageService, formGroupHelper) {
|
4119
4132
|
super(validationMessageService, formGroupHelper);
|
4120
4133
|
this.validationMessageService = validationMessageService;
|
@@ -4155,7 +4168,6 @@ class FileUploadComponent extends FormControlBase {
|
|
4155
4168
|
if (!value) {
|
4156
4169
|
this.formModel.patchValue({
|
4157
4170
|
file: null,
|
4158
|
-
name: null,
|
4159
4171
|
base64FileString: null,
|
4160
4172
|
uploadResult: null
|
4161
4173
|
});
|
@@ -4202,19 +4214,25 @@ class FileUploadComponent extends FormControlBase {
|
|
4202
4214
|
* @param base64FileString Optional: Will have a value provided if the fileOutput is set to base64
|
4203
4215
|
*/
|
4204
4216
|
async processFile(file, base64FileString) {
|
4205
|
-
|
4217
|
+
// Patch the file first to trigger any file validators
|
4218
|
+
this.patchProcessedFile(file, base64FileString);
|
4219
|
+
// If we have any async validators pending we need to wait for them to complete before we know if the form is valid
|
4220
|
+
if (this.formModel.pending) {
|
4221
|
+
await this.formModel.statusChanges.pipe(filter(status => status !== 'PENDING'), take(1), takeUntil(this.componentDestroyed)).toPromise();
|
4222
|
+
}
|
4223
|
+
// Mark the name control as touched so that any validation errors will show
|
4224
|
+
this.formModel.controls.name.markAsTouched();
|
4225
|
+
// Only call the onFileSelected callback to upload the file if the form is valid
|
4226
|
+
if (this.onFileSelected && this.formModel.valid) {
|
4206
4227
|
try {
|
4207
4228
|
let result = await this.onFileSelected(file);
|
4208
|
-
this.
|
4229
|
+
this.formModel.patchValue({ uploadResult: result ?? null });
|
4209
4230
|
}
|
4210
4231
|
catch (e) {
|
4211
4232
|
// Bummer, we're not going to do anything about it though.
|
4212
4233
|
// We are not patching any of the result so any existing information remains
|
4213
4234
|
}
|
4214
4235
|
}
|
4215
|
-
else {
|
4216
|
-
this.patchFileResult(file, base64FileString);
|
4217
|
-
}
|
4218
4236
|
}
|
4219
4237
|
/**
|
4220
4238
|
* Based on the fileOutput return whether this component is expected to deliver a base64 output
|
@@ -4230,18 +4248,13 @@ class FileUploadComponent extends FormControlBase {
|
|
4230
4248
|
* @param base64FileString
|
4231
4249
|
* @param onFileSelectedResult
|
4232
4250
|
*/
|
4233
|
-
|
4251
|
+
patchProcessedFile(file, base64FileString) {
|
4234
4252
|
this.formModel?.patchValue({
|
4235
4253
|
file: file,
|
4236
4254
|
name: file?.name,
|
4237
|
-
base64FileString: base64FileString ?? null
|
4255
|
+
base64FileString: base64FileString ?? null,
|
4256
|
+
uploadResult: null
|
4238
4257
|
});
|
4239
|
-
if (onFileSelectedResult) {
|
4240
|
-
this.formModel.patchValue({ uploadResult: onFileSelectedResult });
|
4241
|
-
}
|
4242
|
-
else {
|
4243
|
-
this.formModel.patchValue({ uploadResult: null });
|
4244
|
-
}
|
4245
4258
|
}
|
4246
4259
|
/** Maps the files to an array of File objects and sends them along
|
4247
4260
|
* to the derived onMultipleFileSelected method in the hosting component
|
@@ -4273,11 +4286,13 @@ class FileUploadComponent extends FormControlBase {
|
|
4273
4286
|
}
|
4274
4287
|
}
|
4275
4288
|
FileUploadComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FileUploadComponent, deps: [{ token: ValidationMessageService }, { token: FormGroupHelper }], target: i0.ɵɵFactoryTarget.Component });
|
4276
|
-
FileUploadComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: FileUploadComponent, selector: "ec-file-upload", inputs: { placeholder: "placeholder", fileType: "fileType", fileOutput: "fileOutput", customExtensions: "customExtensions", onFileSelected: "onFileSelected", onMultipleFilesSelected: "onMultipleFilesSelected", displayType: "displayType", buttonLabel: "buttonLabel", buttonType: "buttonType", multiSelect: "multiSelect" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, read: ElementRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<ec-form-group [label]=\"label\"\r\n [formGroup]=\"formModel\"\r\n [helpPopover]=\"helpPopover\"\r\n [helpPopoverPosition]=\"helpPopoverPosition\"\r\n class=\"mb-0\">\r\n <div class=\"d-flex control-group\">\r\n <div class=\"d-flex flex-grow position-relative\">\r\n <input #fileInput\r\n id=\"{{inputId}}_input\"\r\n type=\"file\"\r\n tabindex=\"-1\"\r\n [attr.accept]=\"fileTypeAccept\"\r\n (change)=\"fileChange($event.target.files)\"\r\n [class.has-value]=\"displayType === 'file' ? formModel?.get('name').value : undefined\"\r\n [attr.multiple]=\"multiSelect ? 'multiple' : undefined\">\r\n
|
4289
|
+
FileUploadComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: FileUploadComponent, selector: "ec-file-upload", inputs: { formModel: "formModel", placeholder: "placeholder", fileType: "fileType", fileOutput: "fileOutput", customExtensions: "customExtensions", onFileSelected: "onFileSelected", onMultipleFilesSelected: "onMultipleFilesSelected", displayType: "displayType", buttonLabel: "buttonLabel", buttonType: "buttonType", multiSelect: "multiSelect" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, read: ElementRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<ec-form-group [label]=\"label\"\r\n [formGroup]=\"formModel\"\r\n [helpPopover]=\"helpPopover\"\r\n [helpPopoverPosition]=\"helpPopoverPosition\"\r\n class=\"mb-0\">\r\n <div class=\"d-flex control-group\">\r\n <div class=\"d-flex flex-grow position-relative\">\r\n <input #fileInput\r\n id=\"{{inputId}}_input\"\r\n type=\"file\"\r\n tabindex=\"-1\"\r\n [attr.accept]=\"fileTypeAccept\"\r\n (change)=\"fileChange($event.target.files)\"\r\n [class.has-value]=\"displayType === 'file' ? formModel?.get('name').value : undefined\"\r\n [attr.multiple]=\"multiSelect ? 'multiple' : undefined\">\r\n <ec-form-control *ngIf=\"displayType === 'file'\"\r\n id=\"{{inputId}}_formControl\"\r\n class=\"text-truncate\"\r\n [required]=\"required\"\r\n [pending]=\"pending || formModel?.pending\">\r\n <input id=\"{{inputId}}_name\"\r\n [formControl]=\"formModel?.get('name')\"\r\n type=\"text\"\r\n [placeholder]=\"placeholder\"\r\n [tabindex]=\"-1\">\r\n </ec-form-control>\r\n </div>\r\n <ec-button *ngIf=\"displayType === 'file'\"\r\n #browseBtn\r\n id=\"{{inputId}}_browseBtn\"\r\n (clicked)=\"fileInput.click()\"\r\n type=\"secondary\"\r\n [tabindex]=\"tabindex\"\r\n [disabled]=\"formModel?.get('name').disabled\"\r\n label=\"Browse\"\r\n [autofocus]=\"autofocus\">\r\n </ec-button>\r\n </div>\r\n <ec-button *ngIf=\"displayType === 'button'\"\r\n id=\"{{inputId}}_btn\"\r\n [pending]=\"pending\"\r\n [type]=\"buttonType\"\r\n [label]=\"buttonLabel ?? 'Browse_TC' | translate\"\r\n (clicked)=\"fileInput.click()\"\r\n style=\"width: 100%;\">\r\n </ec-button>\r\n</ec-form-group>", styles: [":host{display:block;margin-bottom:1rem}ec-form-control{margin-bottom:0}ec-form-control ::ng-deep>.ec-focus-ring{display:none!important}input[type=file]{opacity:0;display:block;position:absolute;top:0;left:0;width:100%;height:100%;z-index:1;cursor:pointer}input[type=file].has-value{width:calc(100% - 1.5rem)}ec-button{--ec-button-border-color-secondary: var(--ec-form-control-border-color);--ec-button-color-icon-secondary: var(--ec-color-icon)}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: ButtonComponent, selector: "ec-button", inputs: ["id", "disabled", "icon", "label", "badge", "tabindex", "type", "pending", "pendingIcon", "customTemplate", "isSubmit", "autofocus"], outputs: ["clicked"] }, { kind: "component", type: FormControlComponent, selector: "ec-form-control", inputs: ["id", "icon", "actionIcon", "showClear", "pending", "required", "readonly"], outputs: ["actionClicked"] }, { kind: "component", type: FormGroupComponent, selector: "ec-form-group", inputs: ["id", "label", "formGroup", "labelPosition", "overrideValidationError", "hideValidationMessage", "helpPopover", "helpPopoverPosition"] }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] });
|
4277
4290
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FileUploadComponent, decorators: [{
|
4278
4291
|
type: Component,
|
4279
|
-
args: [{ selector: "ec-file-upload", template: "<ec-form-group [label]=\"label\"\r\n [formGroup]=\"formModel\"\r\n [helpPopover]=\"helpPopover\"\r\n [helpPopoverPosition]=\"helpPopoverPosition\"\r\n class=\"mb-0\">\r\n <div class=\"d-flex control-group\">\r\n <div class=\"d-flex flex-grow position-relative\">\r\n <input #fileInput\r\n id=\"{{inputId}}_input\"\r\n type=\"file\"\r\n tabindex=\"-1\"\r\n [attr.accept]=\"fileTypeAccept\"\r\n (change)=\"fileChange($event.target.files)\"\r\n [class.has-value]=\"displayType === 'file' ? formModel?.get('name').value : undefined\"\r\n [attr.multiple]=\"multiSelect ? 'multiple' : undefined\">\r\n
|
4280
|
-
}], ctorParameters: function () { return [{ type: ValidationMessageService }, { type: FormGroupHelper }]; }, propDecorators: {
|
4292
|
+
args: [{ selector: "ec-file-upload", template: "<ec-form-group [label]=\"label\"\r\n [formGroup]=\"formModel\"\r\n [helpPopover]=\"helpPopover\"\r\n [helpPopoverPosition]=\"helpPopoverPosition\"\r\n class=\"mb-0\">\r\n <div class=\"d-flex control-group\">\r\n <div class=\"d-flex flex-grow position-relative\">\r\n <input #fileInput\r\n id=\"{{inputId}}_input\"\r\n type=\"file\"\r\n tabindex=\"-1\"\r\n [attr.accept]=\"fileTypeAccept\"\r\n (change)=\"fileChange($event.target.files)\"\r\n [class.has-value]=\"displayType === 'file' ? formModel?.get('name').value : undefined\"\r\n [attr.multiple]=\"multiSelect ? 'multiple' : undefined\">\r\n <ec-form-control *ngIf=\"displayType === 'file'\"\r\n id=\"{{inputId}}_formControl\"\r\n class=\"text-truncate\"\r\n [required]=\"required\"\r\n [pending]=\"pending || formModel?.pending\">\r\n <input id=\"{{inputId}}_name\"\r\n [formControl]=\"formModel?.get('name')\"\r\n type=\"text\"\r\n [placeholder]=\"placeholder\"\r\n [tabindex]=\"-1\">\r\n </ec-form-control>\r\n </div>\r\n <ec-button *ngIf=\"displayType === 'file'\"\r\n #browseBtn\r\n id=\"{{inputId}}_browseBtn\"\r\n (clicked)=\"fileInput.click()\"\r\n type=\"secondary\"\r\n [tabindex]=\"tabindex\"\r\n [disabled]=\"formModel?.get('name').disabled\"\r\n label=\"Browse\"\r\n [autofocus]=\"autofocus\">\r\n </ec-button>\r\n </div>\r\n <ec-button *ngIf=\"displayType === 'button'\"\r\n id=\"{{inputId}}_btn\"\r\n [pending]=\"pending\"\r\n [type]=\"buttonType\"\r\n [label]=\"buttonLabel ?? 'Browse_TC' | translate\"\r\n (clicked)=\"fileInput.click()\"\r\n style=\"width: 100%;\">\r\n </ec-button>\r\n</ec-form-group>", styles: [":host{display:block;margin-bottom:1rem}ec-form-control{margin-bottom:0}ec-form-control ::ng-deep>.ec-focus-ring{display:none!important}input[type=file]{opacity:0;display:block;position:absolute;top:0;left:0;width:100%;height:100%;z-index:1;cursor:pointer}input[type=file].has-value{width:calc(100% - 1.5rem)}ec-button{--ec-button-border-color-secondary: var(--ec-form-control-border-color);--ec-button-color-icon-secondary: var(--ec-color-icon)}\n"] }]
|
4293
|
+
}], ctorParameters: function () { return [{ type: ValidationMessageService }, { type: FormGroupHelper }]; }, propDecorators: { formModel: [{
|
4294
|
+
type: Input
|
4295
|
+
}], placeholder: [{
|
4281
4296
|
type: Input
|
4282
4297
|
}], fileType: [{
|
4283
4298
|
type: Input
|
@@ -10579,6 +10594,10 @@ class PageBaseComponent {
|
|
10579
10594
|
*/
|
10580
10595
|
async onSave(event) {
|
10581
10596
|
this.formGroup.markAllAsTouched();
|
10597
|
+
// If the form has pending async validators, wait for it them to complete before proceeding
|
10598
|
+
if (this.formGroup.pending) {
|
10599
|
+
await this.formGroup.statusChanges.pipe(filter(status => status !== 'PENDING'), take(1), takeUntil(this.destroyed)).toPromise();
|
10600
|
+
}
|
10582
10601
|
if (this.formGroup.valid) {
|
10583
10602
|
await this.save();
|
10584
10603
|
}
|