@energycap/components 0.39.21-ECAP-25650-file-upload-validation-support.20240806-0942 → 0.39.21-ECAP-25650-file-upload-validation-support.20240806-1534
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 +48 -31
- package/esm2020/lib/shared/page/page-base/page-base.component.mjs +5 -1
- package/fesm2015/energycap-components.mjs +53 -31
- package/fesm2015/energycap-components.mjs.map +1 -1
- package/fesm2020/energycap-components.mjs +51 -30
- package/fesm2020/energycap-components.mjs.map +1 -1
- package/lib/controls/file-upload/file-upload.component.d.ts +12 -9
- package/package.json +1 -1
@@ -4106,7 +4106,9 @@ const FileTypeExtensions = {
|
|
4106
4106
|
};
|
4107
4107
|
class FileUploadComponent extends FormControlBase {
|
4108
4108
|
// static class to create the form group from a parent component
|
4109
|
-
static getFormModel(validators, disabled = false,
|
4109
|
+
static getFormModel(validators, disabled = false,
|
4110
|
+
/** Any validators required to make sure the selected file is valid. It is recommended that you use `FileUploadComponent.getFileValidator` to help construct the validator(s). NOTE: This currently only works when multiSelect is false. */
|
4111
|
+
fileValidators) {
|
4110
4112
|
let formGroup = new FormGroup({
|
4111
4113
|
file: new FormControl({ value: null, disabled: disabled }, { validators: validators, asyncValidators: fileValidators }),
|
4112
4114
|
name: new FormControl({ value: null, disabled: disabled }, validators),
|
@@ -4118,10 +4120,18 @@ class FileUploadComponent extends FormControlBase {
|
|
4118
4120
|
}
|
4119
4121
|
return formGroup;
|
4120
4122
|
}
|
4123
|
+
/**
|
4124
|
+
* Helper function that returns an async validator to be used with the file upload control.
|
4125
|
+
* This is useful for when the file needs to be validated before it can be uploaded.
|
4126
|
+
*
|
4127
|
+
* @param callback The callback function that will be called to validate the file. Parameters for the callback are the file and the base64 string for the file.
|
4128
|
+
* base64 is null if the fileOutput input on the FileUploadComponent is set to raw. Using fileOutput set to base64 is recommended for images.
|
4129
|
+
*/
|
4121
4130
|
static getFileValidator(callback) {
|
4122
4131
|
return async (control) => {
|
4123
4132
|
if (control.value && control.parent) {
|
4124
4133
|
let file = control.value;
|
4134
|
+
// For images, we need the base64 string to validate image dimensions
|
4125
4135
|
let base64 = control.parent.get('base64FileString')?.value;
|
4126
4136
|
return await callback(file, base64);
|
4127
4137
|
}
|
@@ -4173,7 +4183,8 @@ class FileUploadComponent extends FormControlBase {
|
|
4173
4183
|
});
|
4174
4184
|
}
|
4175
4185
|
});
|
4176
|
-
// Sync errors from the file control to the name control whenever the file control status changes
|
4186
|
+
// Sync errors from the file control to the name control whenever the file control status changes.
|
4187
|
+
// The name control is the only one displayed to the user so we need to show the errors there.
|
4177
4188
|
this.formModel.get('file')?.statusChanges.pipe(takeUntil(this.componentDestroyed)).subscribe(() => {
|
4178
4189
|
const errors = this.formModel.get('file')?.errors ?? null;
|
4179
4190
|
this.formModel.get('name')?.setErrors(errors);
|
@@ -4218,26 +4229,47 @@ class FileUploadComponent extends FormControlBase {
|
|
4218
4229
|
* @param file
|
4219
4230
|
* @param base64FileString Optional: Will have a value provided if the fileOutput is set to base64
|
4220
4231
|
*/
|
4221
|
-
async processFile(file, base64FileString) {
|
4232
|
+
async processFile(file, base64FileString = null) {
|
4233
|
+
// If we have async validators on the file control we need to do validation before we trigger the upload
|
4234
|
+
const validateBeforeUpload = !!this.formModel.controls.file.asyncValidator;
|
4235
|
+
if (validateBeforeUpload) {
|
4236
|
+
await this.validateFile(file, base64FileString);
|
4237
|
+
}
|
4238
|
+
if (this.onFileSelected) {
|
4239
|
+
// Only call the onFileSelected callback to upload the file if the form group is valid
|
4240
|
+
if (this.formModel.valid) {
|
4241
|
+
try {
|
4242
|
+
let result = await this.onFileSelected(file);
|
4243
|
+
// If we did validation, just patch the form result because the file is already in the form
|
4244
|
+
if (validateBeforeUpload) {
|
4245
|
+
this.formModel.patchValue({ uploadResult: result ?? null });
|
4246
|
+
}
|
4247
|
+
else {
|
4248
|
+
this.formModel.patchValue({ file, name: file.name, base64FileString, uploadResult: result ?? null });
|
4249
|
+
}
|
4250
|
+
}
|
4251
|
+
catch (e) {
|
4252
|
+
// Bummer, we're not going to do anything about it though.
|
4253
|
+
// We are not patching any of the result so any existing information remains
|
4254
|
+
}
|
4255
|
+
}
|
4256
|
+
// If we don't have an onFileSelected callback we just patch the form model.
|
4257
|
+
// In the case of pre-upload validation the form already has the file so we don't want to patch again.
|
4258
|
+
}
|
4259
|
+
else if (!validateBeforeUpload) {
|
4260
|
+
this.formModel.patchValue({ file, name: file.name, base64FileString, uploadResult: null });
|
4261
|
+
}
|
4262
|
+
}
|
4263
|
+
/** Patches the form with the selected file in order to trigger control validation */
|
4264
|
+
async validateFile(file, base64FileString = null) {
|
4222
4265
|
// Patch the file first to trigger any file validators
|
4223
|
-
this.
|
4266
|
+
this.formModel.patchValue({ file, name: file.name, base64FileString, uploadResult: null });
|
4224
4267
|
// If we have any async validators pending we need to wait for them to complete before we know if the form is valid
|
4225
4268
|
if (this.formModel.pending) {
|
4226
4269
|
await this.formModel.statusChanges.pipe(filter(status => status !== 'PENDING'), take(1), takeUntil(this.componentDestroyed)).toPromise();
|
4227
4270
|
}
|
4228
4271
|
// Mark the name control as touched so that any validation errors will show
|
4229
4272
|
this.formModel.controls.name.markAsTouched();
|
4230
|
-
// Only call the onFileSelected callback to upload the file if the form is valid
|
4231
|
-
if (this.onFileSelected && this.formModel.valid) {
|
4232
|
-
try {
|
4233
|
-
let result = await this.onFileSelected(file);
|
4234
|
-
this.formModel.patchValue({ uploadResult: result ?? null });
|
4235
|
-
}
|
4236
|
-
catch (e) {
|
4237
|
-
// Bummer, we're not going to do anything about it though.
|
4238
|
-
// We are not patching any of the result so any existing information remains
|
4239
|
-
}
|
4240
|
-
}
|
4241
4273
|
}
|
4242
4274
|
/**
|
4243
4275
|
* Based on the fileOutput return whether this component is expected to deliver a base64 output
|
@@ -4246,21 +4278,6 @@ class FileUploadComponent extends FormControlBase {
|
|
4246
4278
|
isBase64FileOutput() {
|
4247
4279
|
return this.fileOutput === 'base64';
|
4248
4280
|
}
|
4249
|
-
/**
|
4250
|
-
* When the file was selected and processed patch the file information that the hosting form will
|
4251
|
-
* be looking for.
|
4252
|
-
* @param file
|
4253
|
-
* @param base64FileString
|
4254
|
-
* @param onFileSelectedResult
|
4255
|
-
*/
|
4256
|
-
patchProcessedFile(file, base64FileString) {
|
4257
|
-
this.formModel?.patchValue({
|
4258
|
-
file: file,
|
4259
|
-
name: file?.name,
|
4260
|
-
base64FileString: base64FileString ?? null,
|
4261
|
-
uploadResult: null
|
4262
|
-
});
|
4263
|
-
}
|
4264
4281
|
/** Maps the files to an array of File objects and sends them along
|
4265
4282
|
* to the derived onMultipleFileSelected method in the hosting component
|
4266
4283
|
*/
|
@@ -10598,6 +10615,8 @@ class PageBaseComponent {
|
|
10598
10615
|
* @param event
|
10599
10616
|
*/
|
10600
10617
|
async onSave(event) {
|
10618
|
+
// Show the saving overlay in case we have async validators in play
|
10619
|
+
this.showStatus(PageStatus.Saving);
|
10601
10620
|
this.formGroup.markAllAsTouched();
|
10602
10621
|
// If the form has pending async validators, wait for it them to complete before proceeding
|
10603
10622
|
if (this.formGroup.pending) {
|
@@ -10607,6 +10626,8 @@ class PageBaseComponent {
|
|
10607
10626
|
await this.save();
|
10608
10627
|
}
|
10609
10628
|
else {
|
10629
|
+
// Remove the saving overlay to display any errors
|
10630
|
+
this.showStatus(PageStatus.Loaded);
|
10610
10631
|
// Only show the banner with the generic message if the parent component hasn't already set one
|
10611
10632
|
// by implementing onSave for additional validation
|
10612
10633
|
if (this.errors === '') {
|