@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.
@@ -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';
@@ -738,6 +738,9 @@ class ValidationMessageService {
738
738
  case 'domain':
739
739
  translationObservables.push(this.translate.get('DomainValidationMessage_SC'));
740
740
  break;
741
+ case 'invalidFile':
742
+ translationObservables.push(this.translate.get('is invalid'));
743
+ break;
741
744
  default:
742
745
  break;
743
746
  }
@@ -4132,18 +4135,29 @@ const FileTypeExtensions = {
4132
4135
  };
4133
4136
  class FileUploadComponent extends FormControlBase {
4134
4137
  // static class to create the form group from a parent component
4135
- static getFormModel(validators, disabled = false) {
4136
- let formGroup = new UntypedFormGroup({
4137
- file: new UntypedFormControl({ value: null, disabled: disabled }, validators),
4138
- name: new UntypedFormControl({ value: null, disabled: disabled }, validators),
4139
- base64FileString: new UntypedFormControl(null),
4140
- uploadResult: new UntypedFormControl(null),
4138
+ static getFormModel(validators, disabled = false, fileValidators) {
4139
+ let formGroup = new FormGroup({
4140
+ file: new FormControl({ value: null, disabled: disabled }, validators),
4141
+ name: new FormControl({ value: null, disabled: disabled }, { validators: validators, asyncValidators: fileValidators }),
4142
+ base64FileString: new FormControl(null),
4143
+ uploadResult: new FormControl(null),
4141
4144
  });
4142
4145
  if (disabled) {
4143
4146
  formGroup.disable();
4144
4147
  }
4145
4148
  return formGroup;
4146
4149
  }
4150
+ static getFileValidator(callback) {
4151
+ return (nameControl) => __awaiter(this, void 0, void 0, function* () {
4152
+ var _a, _b, _c;
4153
+ if (nameControl.value && nameControl.parent && ((_a = nameControl.parent.get('file')) === null || _a === void 0 ? void 0 : _a.value)) {
4154
+ let file = (_b = nameControl.parent.get('file')) === null || _b === void 0 ? void 0 : _b.value;
4155
+ let base64 = (_c = nameControl.parent.get('base64FileString')) === null || _c === void 0 ? void 0 : _c.value;
4156
+ return yield callback(file, base64);
4157
+ }
4158
+ return null;
4159
+ });
4160
+ }
4147
4161
  constructor(validationMessageService, formGroupHelper) {
4148
4162
  super(validationMessageService, formGroupHelper);
4149
4163
  this.validationMessageService = validationMessageService;
@@ -4185,7 +4199,6 @@ class FileUploadComponent extends FormControlBase {
4185
4199
  if (!value) {
4186
4200
  this.formModel.patchValue({
4187
4201
  file: null,
4188
- name: null,
4189
4202
  base64FileString: null,
4190
4203
  uploadResult: null
4191
4204
  });
@@ -4235,19 +4248,25 @@ class FileUploadComponent extends FormControlBase {
4235
4248
  */
4236
4249
  processFile(file, base64FileString) {
4237
4250
  return __awaiter(this, void 0, void 0, function* () {
4238
- if (this.onFileSelected) {
4251
+ // Patch the file first to trigger any file validators
4252
+ this.patchProcessedFile(file, base64FileString);
4253
+ // If we have any async validators pending we need to wait for them to complete before we know if the form is valid
4254
+ if (this.formModel.pending) {
4255
+ yield this.formModel.statusChanges.pipe(filter(status => status !== 'PENDING'), take(1), takeUntil(this.componentDestroyed)).toPromise();
4256
+ }
4257
+ // Mark the name control as touched so that any validation errors will show
4258
+ this.formModel.controls.name.markAsTouched();
4259
+ // Only call the onFileSelected callback to upload the file if the form is valid
4260
+ if (this.onFileSelected && this.formModel.valid) {
4239
4261
  try {
4240
4262
  let result = yield this.onFileSelected(file);
4241
- this.patchFileResult(file, base64FileString, result);
4263
+ this.formModel.patchValue({ uploadResult: result !== null && result !== void 0 ? result : null });
4242
4264
  }
4243
4265
  catch (e) {
4244
4266
  // Bummer, we're not going to do anything about it though.
4245
4267
  // We are not patching any of the result so any existing information remains
4246
4268
  }
4247
4269
  }
4248
- else {
4249
- this.patchFileResult(file, base64FileString);
4250
- }
4251
4270
  });
4252
4271
  }
4253
4272
  /**
@@ -4264,19 +4283,14 @@ class FileUploadComponent extends FormControlBase {
4264
4283
  * @param base64FileString
4265
4284
  * @param onFileSelectedResult
4266
4285
  */
4267
- patchFileResult(file, base64FileString, onFileSelectedResult) {
4286
+ patchProcessedFile(file, base64FileString) {
4268
4287
  var _a;
4269
4288
  (_a = this.formModel) === null || _a === void 0 ? void 0 : _a.patchValue({
4270
4289
  file: file,
4271
4290
  name: file === null || file === void 0 ? void 0 : file.name,
4272
- base64FileString: base64FileString !== null && base64FileString !== void 0 ? base64FileString : null
4291
+ base64FileString: base64FileString !== null && base64FileString !== void 0 ? base64FileString : null,
4292
+ uploadResult: null
4273
4293
  });
4274
- if (onFileSelectedResult) {
4275
- this.formModel.patchValue({ uploadResult: onFileSelectedResult });
4276
- }
4277
- else {
4278
- this.formModel.patchValue({ uploadResult: null });
4279
- }
4280
4294
  }
4281
4295
  /** Maps the files to an array of File objects and sends them along
4282
4296
  * to the derived onMultipleFileSelected method in the hosting component
@@ -4313,11 +4327,13 @@ class FileUploadComponent extends FormControlBase {
4313
4327
  }
4314
4328
  }
4315
4329
  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 });
4316
- 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 <ec-form-control *ngIf=\"displayType === 'file'\"\r\n id=\"{{inputId}}_formControl\"\r\n class=\"text-truncate\"\r\n [required]=\"required\"\r\n [pending]=\"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" }] });
4330
+ 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" }] });
4317
4331
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FileUploadComponent, decorators: [{
4318
4332
  type: Component,
4319
- 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\">\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"] }]
4320
- }], ctorParameters: function () { return [{ type: ValidationMessageService }, { type: FormGroupHelper }]; }, propDecorators: { placeholder: [{
4333
+ 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"] }]
4334
+ }], ctorParameters: function () { return [{ type: ValidationMessageService }, { type: FormGroupHelper }]; }, propDecorators: { formModel: [{
4335
+ type: Input
4336
+ }], placeholder: [{
4321
4337
  type: Input
4322
4338
  }], fileType: [{
4323
4339
  type: Input
@@ -10696,6 +10712,10 @@ class PageBaseComponent {
10696
10712
  onSave(event) {
10697
10713
  return __awaiter(this, void 0, void 0, function* () {
10698
10714
  this.formGroup.markAllAsTouched();
10715
+ // If the form has pending async validators, wait for it them to complete before proceeding
10716
+ if (this.formGroup.pending) {
10717
+ yield this.formGroup.statusChanges.pipe(filter(status => status !== 'PENDING'), take(1), takeUntil(this.destroyed)).toPromise();
10718
+ }
10699
10719
  if (this.formGroup.valid) {
10700
10720
  yield this.save();
10701
10721
  }