I'm trying to create a sophisticated file uploader using Angular 16 frontend with a Laravel 11 backend, and i searched and found that ngx-uploader is suitable for the options i need in my file uploader (using drag-and-drop and file browser, showing uplaod progress bar, total number of files and how many been uploaded so far, list of succesfully uploaded files) but i dont seem to be able to make it work for some reason i find it complicated i tried different things, like modifying, my component code; the interfaces.d.ts code, i also looked for tutrials but nothing helped, let me share my code with you : <app-alert></app-alert> <div class="container"> <div class="row py-5"> <div class="col-lg-12"> <div class="upload-container"> <h2>{{('Upload.Upload' | translate)}}</h2> <!-- Drop Container --> <div class="drop-container" ngFileDrop [options]="options" (uploadOutput)="onUploadOutput($event)" [uploadInput]="uploadInput" [ngClass]="{ 'is-drop-over': dragOver }"> <div class="upload-icon"> <img src="assets/imgs/Upload icon.svg" alt="Upload Icon"> </div> <h3>{{('Upload.Drag & drop files or' | translate)}} <label class="browse-link" (click)="onBrowseClick()">{{('Upload.Browse' | translate)}}</label> </h3> <p class="supported-formats">{{('Upload.Supported formats: PDF, Word and PPT' | translate)}}</p> <input type="file" #fileInput ngFileSelect [options]="options" (uploadOutput)="onUploadOutput($event)" [uploadInput]="uploadInput" multiple hidden /> </div> <!-- Completed Upload Count --> <div class="upload-status"> Uploading - {{ completedUploads }}/{{ files.length }} files </div> <!-- File List with Progress and Error Messages --> <div class="file-list"> <h3 *ngIf="files.length>0">Uploaded</h3> <div *ngFor="let file of files" class="file-item" [ngClass]="{'error': file.errorStatus, 'success': file.progress?.status === UploadStatus.Done}"> <span>{{ file.name }}</span> <!-- Remove button for each file --> <button class="remove-btn" (click)="removeFile(file.id)"> <i class="bi bi-trash3"></i> </button> <!-- Display progress for each file --> <div *ngIf="file.progress?.status === UploadStatus.Uploading" class="progress-bar"> <div class="progress" [style.width.%]="file.progress?.data?.percentage"></div> <span>{{ file.progress?.data?.percentage }}%</span> </div> <!-- Error message in red if there's an error --> <span *ngIf="file.errorStatus" class="error-message"> {{ file.errorMessage || 'Upload failed'}} </span> </div> </div> <!-- Upload Button --> <app-button-green (click)="startUpload()">Upload File</app-button-green> </div> </div> </div> </div> here is my ts file: import { HttpClient } from '@angular/common/http'; import { Component, ElementRef, EventEmitter, ViewChild } from '@angular/core'; import { UploadOutput, UploadInput, UploadFile, UploaderOptions, UploadStatus } from 'ngx-uploader'; import { ProfileUpdateService } from 'src/app/services/profile-update.service'; import { environment } from 'src/environments/environment.development'; @Component({ selector: 'app-upload-file', templateUrl: './upload-file.component.html', styleUrls: ['./upload-file.component.css'] }) export class UploadFileComponent { options: UploaderOptions; files: UploadFile[] = []; uploadInput: EventEmitter<UploadInput>; dragOver?: boolean; uploadUrl = `${environment.apiUrl}/upload_files`; // Adjust your API URL as needed @ViewChild('fileInput') fileInput!: ElementRef; // Reference to the file input completedUploads: number = 0; user_id=0; public UploadStatus = UploadStatus; // Make UploadStatus available in template constructor(private userService: ProfileUpdateService) { this.options = { concurrency: 1, maxUploads: 3, maxFileSize: 1000000, allowedContentTypes:['.pdf','.docx','.pdf','.pptx'] }; // Adjust options based on needs this.uploadInput = new EventEmitter<UploadInput>(); // Initialize the event emitter this.fetchUserId(); } fetchUserId(): void { this.userService.getUser().subscribe(response => { this.user_id = response.id; // Store user ID in a class variable }); } onUploadOutput(output: UploadOutput): void { switch (output.type) { case 'addedToQueue': if (typeof output.file !== 'undefined') { this.files.push(output.file); } break; case 'allAddedToQueue': this.startUpload(); // Start the upload process after adding files break; case 'uploading': if (typeof output.file !== 'undefined') { // update current data in files array for uploading file const index = this.files.findIndex(file => typeof output.file !== 'undefined' && file.id === output.file.id); this.files[index] = output.file; } break; case 'removed': // remove file from array when removed this.files = this.files.filter((file: UploadFile) => file !== output.file); break; case 'dragOver': this.dragOver = true; break; case 'dragOut': case 'drop': this.dragOver = false; break; case 'done': // The file is downloaded break; } } updateCompletedUploads() { this.completedUploads = this.files.filter(file => file.progress?.status === UploadStatus.Done).length; // Count completed uploads } startUpload(): void { const uploadEvent: UploadInput = { type: 'uploadAll', url: this.uploadUrl, method: 'POST', user_id: this.user_id }; this.uploadInput.emit(uploadEvent); // Emit the upload event } removeFile(id: string): void { this.files = this.files.filter(file => file.id !== id); // Remove file from list this.updateCompletedUploads(); // Update completed uploads count } onBrowseClick(): void { this.fileInput.nativeElement.click(); // Trigger the hidden file input } } here is the interfaces file: import { Subscription } from 'rxjs'; export interface UploaderOptions { concurrency: number; allowedContentTypes?: string[]; maxUploads?: number; maxFileSize?: number; } export interface BlobFile extends Blob { name: string; } export declare enum UploadStatus { Queue = 0, Uploading = 1, Done = 2, Cancelled = 3 } export interface UploadProgress { status: UploadStatus; data?: { percentage: number; speed: number; speedHuman: string; startTime: number | null; endTime: number | null; eta: number | null; etaHuman: string | null; }; } export interface UploadFile { id: string; fileIndex?: number; lastModifiedDate?: Date; name?: string; file_size?: number; type?: string; form?: FormData; progress?: UploadProgress; response?: any; responseStatus?: number; sub?: Subscription | any; nativeFile?: File; responseHeaders?: { [key: string]: string; }; errorStatus?: boolean; // Add this line errorMessage?: string; // Add this if you need an error message } export interface UploadOutput { type: 'addedToQueue' | 'allAddedToQueue' | 'uploading' | 'done' | 'start' | 'cancelled' | 'dragOver' | 'dragOut' | 'drop' | 'removed' | 'removedAll' | 'rejected'; file?: UploadFile; nativeFile?: File; } export interface UploadInput { type: 'uploadAll' | 'uploadFile' | 'cancel' | 'cancelAll' | 'remove' | 'removeAll'; url?: string; method?: string; id?: string; fieldName?: string; fileIndex?: number; user_id?: number; file?: UploadFile; data?: { [key: string]: string | Blob; }; headers?: { [key: string]: string; }; includeWebKitFormBoundary?: boolean; withCredentials?: boolean; } and here is my laravel function : public function upload(UploadedFileRequest $request) { try { // Initialize an array to hold the paths of uploaded files $filePaths = []; if ($request->hasfile('filePaths')) { $count = 0; foreach ($request->file('filePaths') as $file) { $f = new UploadedFile(); $f->user_id = $file->user_id; $f->file_size = $file->file_size; $fileName = str_replace(' ', '', $file->getClientOriginalName() . '(' . time() . ').' . $file->getClientOriginalExtension()); $f->file_path = $file->storeAs('uploadedFiles', $fileName); $f->save(); $count++; $filePaths[] = $f->file_path; } } // Return a successful response with the file paths return response()->json([ 'message' => __('exceptions.Files uploaded successfully'), 'paths' => $filePaths, ]); } catch (Error $e) { Log::error('Error: ' . $e->getMessage()); return response()->json([__('validation.error') => $e->getMessage()], 422); } catch (\Throwable $e) { Log::error('Error: ' . $e->getMessage()); return response()->json([__('validation.error') => $e->getMessage()], 422); } catch (\Exception $e) { Log::error('Error: ' . $e->getMessage()); return response()->json([__('validation.error') => $e->getMessage()], 422); } } Continue reading...