From f035d4ece36a0810a166be111c778b0c500329cc Mon Sep 17 00:00:00 2001 From: Yanek Voloshchuk Date: Mon, 16 Sep 2024 12:02:30 +0200 Subject: [PATCH] update upload and add remove to upload-file component --- .../file-upload/file-upload.component.html | 18 ++++- .../lib/file-upload/file-upload.component.ts | 79 +++++++++++++------ .../upload-demo-api-spec.component.html | 77 ++++++++++++++++++ .../upload-demo-api-spec.component.scss | 24 ++++++ .../upload-demo-api-spec.component.ts | 12 +++ .../upload-demo/upload-demo.component.html | 16 ++-- .../upload-demo/upload-demo.component.ts | 3 +- .../upload-file/upload-file.component.html | 2 + .../upload-file/upload-file.component.ts | 1 + 9 files changed, 194 insertions(+), 38 deletions(-) create mode 100644 src/app/component-demos/upload-demo/upload-demo-api-spec/upload-demo-api-spec.component.html create mode 100644 src/app/component-demos/upload-demo/upload-demo-api-spec/upload-demo-api-spec.component.scss create mode 100644 src/app/component-demos/upload-demo/upload-demo-api-spec/upload-demo-api-spec.component.ts diff --git a/projects/material-addons/src/lib/file-upload/file-upload.component.html b/projects/material-addons/src/lib/file-upload/file-upload.component.html index 0c478b95..7946fc47 100644 --- a/projects/material-addons/src/lib/file-upload/file-upload.component.html +++ b/projects/material-addons/src/lib/file-upload/file-upload.component.html @@ -9,20 +9,30 @@ #fileInput (change)="uploadFile($event.target.files)" (click)="fileInput.value = null" - [accept]="acceptForInput" + [accept]="acceptedFileTypes" [id]="id" [multiple]="multiple" hidden type="file" /> - vertical_align_top - {{ text ? text : 'Upload' }} + + {{ fileList[0].name }} + + + + vertical_align_top + {{ text ? text : 'Upload' }} + - {{ file.name }} + + {{ file.name }} + delete_forever + diff --git a/projects/material-addons/src/lib/file-upload/file-upload.component.ts b/projects/material-addons/src/lib/file-upload/file-upload.component.ts index 9884e92b..b2adb2f0 100644 --- a/projects/material-addons/src/lib/file-upload/file-upload.component.ts +++ b/projects/material-addons/src/lib/file-upload/file-upload.component.ts @@ -22,48 +22,83 @@ export class FileUploadComponent implements OnInit { @Input() accept: string[]; @Input() text: string; @Input() showFileList: boolean = false; + @Input() removable: boolean = true; @Output() fileEmitter = new EventEmitter(); @Output() errorEmitter = new EventEmitter(); fileList: File[] = []; - acceptForInput: string[] = []; - private uploadError: boolean = false; + acceptedFileTypes: string[] = []; ngOnInit(): void { + this.setAcceptedFileTypes(); + } + + private setAcceptedFileTypes(): void { if (this.accept?.length) { - this.accept.forEach((accepted) => this.acceptForInput.push(`.${accepted}`)); + this.acceptedFileTypes = this.accept.map(ext => `.${ext.toLowerCase()}`); } } - uploadFile(fileList: FileList): void { - if (!this.multiple && (fileList.length > 1 || this.fileList.length === 1)) { - this.errorEmitter.emit('ONLY_SINGLE_FILE'); - this.uploadError = false; + uploadFile(files: FileList): void { + const fileArray = Array.from(files); + + if (!this.validateFileList(fileArray)) { return; } - if (this.accept && this.accept.length > 0) { - for (let i = 0; i < fileList.length; i++) { - this.getFileEnding(fileList.item(i).name); - } + + this.addFiles(fileArray); + this.fileEmitter.emit(this.createFileListFromArray(this.fileList)); + } + + private validateFileList(fileArray: File[]): boolean { + if (!this.multiple && fileArray.length > 1) { + this.emitError('ONLY_SINGLE_FILE'); + return false; } - if (!this.uploadError) { - for (let i = 0; i < fileList.length; i++) { - this.fileList.push(fileList.item(i)); + + for (const file of fileArray) { + if (!this.isAcceptedFileType(file.name)) { + this.emitError('FILETYPE_NOT_SUPPORTED'); + return false; } - this.fileEmitter.emit(fileList); } - this.uploadError = false; + + return true; + } + + private emitError(errorType: UploadError): void { + this.errorEmitter.emit(errorType); + } + + private isAcceptedFileType(fileName: string): boolean { + const fileExtension = fileName.split('.').pop()?.toLowerCase(); + return this.acceptedFileTypes.includes(`.${fileExtension}`); } - getFileEnding(name: string): void { - const ending = name.substring(name.lastIndexOf('.') + 1); - if (this.accept.filter((a) => a.toLowerCase() === ending.toLowerCase()).length === 0) { - this.errorEmitter.emit('FILETYPE_NOT_SUPPORTED'); - this.uploadError = true; + private addFiles(fileArray: File[]): void { + if (!this.multiple) { + this.fileList = []; } + this.fileList.push(...fileArray); } - openFile(file: File) { + openFile(file: File): void { window.open(window.URL.createObjectURL(file)); } + + remove(file: File): void { + this.fileList = this.fileList.filter(f => f !== file); + this.fileEmitter.emit(this.createFileListFromArray(this.fileList)); + } + + private createFileListFromArray(files: File[]): FileList { + const dataTransfer = new DataTransfer(); + files.forEach(file => dataTransfer.items.add(file)); + return dataTransfer.files; + } + + hasSingleFile(): boolean { + return !this.multiple && this.fileList.length === 1; + } + } diff --git a/src/app/component-demos/upload-demo/upload-demo-api-spec/upload-demo-api-spec.component.html b/src/app/component-demos/upload-demo/upload-demo-api-spec/upload-demo-api-spec.component.html new file mode 100644 index 00000000..eaa5e067 --- /dev/null +++ b/src/app/component-demos/upload-demo/upload-demo-api-spec/upload-demo-api-spec.component.html @@ -0,0 +1,77 @@ +
+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDefault ValueDescription
idstring'' + HTML id of the element. +
multiplebooleanif false only 1 document can be added, otherwise you can add as much documents as you want.
acceptstring[]'[]'is a string array which contains all valid document types.
textstring'Upload'Text in the Upload Field.
showFileListbooleanfalseShows the list of added files.
removablebooleantrueUploaded file can be deleted using icon in chip.
+ +

Events

+ + + + + + + + + + + + + + + + + + + + + +
EventDescription
fileEmitterEmits when file is uploaded/removed. Contains file list
errorEmitter(ErrorType) ONLY_SINGLE_FILE: if only 1 File is allowed and user tries to add more than 1 File in 1 dialog.
errorEmitter(ErrorType) FILETYPE_NOT_SUPPORTED: if user tries to add unsupported file type
+
diff --git a/src/app/component-demos/upload-demo/upload-demo-api-spec/upload-demo-api-spec.component.scss b/src/app/component-demos/upload-demo/upload-demo-api-spec/upload-demo-api-spec.component.scss new file mode 100644 index 00000000..421d448b --- /dev/null +++ b/src/app/component-demos/upload-demo/upload-demo-api-spec/upload-demo-api-spec.component.scss @@ -0,0 +1,24 @@ +.api-specification { + font-family: Arial, sans-serif; +} + +.api-specification h2 { + color: #333; +} + +.api-specification table { + width: 100%; + border-collapse: collapse; + margin-bottom: 20px; +} + +.api-specification th, +.api-specification td { + border: 1px solid #ccc; + padding: 8px; + text-align: left; +} + +.api-specification th { + background-color: #f2f2f2; +} diff --git a/src/app/component-demos/upload-demo/upload-demo-api-spec/upload-demo-api-spec.component.ts b/src/app/component-demos/upload-demo/upload-demo-api-spec/upload-demo-api-spec.component.ts new file mode 100644 index 00000000..2cc53d0b --- /dev/null +++ b/src/app/component-demos/upload-demo/upload-demo-api-spec/upload-demo-api-spec.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-upload-demo-api-spec', + standalone: true, + imports: [], + templateUrl: './upload-demo-api-spec.component.html', + styleUrl: './upload-demo-api-spec.component.scss' +}) +export class UploadDemoApiSpecComponent { + +} diff --git a/src/app/component-demos/upload-demo/upload-demo.component.html b/src/app/component-demos/upload-demo/upload-demo.component.html index da956ada..3212e49e 100644 --- a/src/app/component-demos/upload-demo/upload-demo.component.html +++ b/src/app/component-demos/upload-demo/upload-demo.component.html @@ -2,18 +2,10 @@

Behavior

    -
  • clickable with dialog to select files
  • +
  • Clickable with dialog to select files
  • Drag And Drop Functionality
  • -
- -
-

Inputs

-
    -
  • accept: is a string array which contains all valid document types
  • -
  • multiple: if false only 1 document can be added, otherwise you can add as much documents as you want
  • -
  • text: Text in the Upload Field
  • -
  • id: HTML id of the element
  • -
  • showFileList: Shows the list of added files
  • +
  • Replace file with a new one in single upload mode
  • +
  • Show the

@@ -37,3 +29,5 @@

Output

+

API Specification

+ diff --git a/src/app/component-demos/upload-demo/upload-demo.component.ts b/src/app/component-demos/upload-demo/upload-demo.component.ts index 5b14f981..6ec8ed9f 100644 --- a/src/app/component-demos/upload-demo/upload-demo.component.ts +++ b/src/app/component-demos/upload-demo/upload-demo.component.ts @@ -3,13 +3,14 @@ import { Example } from '../../components/example-viewer/example.class'; import { UploadFileComponent } from '../../example-components/upload-file/upload-file.component'; import { ExampleViewerComponent } from '../../components/example-viewer/example-viewer.component'; import { TextCodeComponent } from '../../components/text-code/text-code.component'; +import {UploadDemoApiSpecComponent} from './upload-demo-api-spec/upload-demo-api-spec.component'; @Component({ selector: 'app-upload-demo', templateUrl: './upload-demo.component.html', styleUrl: './upload-demo.component.scss', standalone: true, - imports: [TextCodeComponent, ExampleViewerComponent], + imports: [TextCodeComponent, ExampleViewerComponent, UploadDemoApiSpecComponent], }) export class UploadDemoComponent { uploadComponent = new Example(UploadFileComponent, 'upload-file', 'upload'); diff --git a/src/app/example-components/upload-file/upload-file.component.html b/src/app/example-components/upload-file/upload-file.component.html index ec316452..cd418baf 100644 --- a/src/app/example-components/upload-file/upload-file.component.html +++ b/src/app/example-components/upload-file/upload-file.component.html @@ -7,12 +7,14 @@ {{ 'Allow Multiple Uploads' }} {{ 'Show File List' }} +{{ 'Removable File' }}