Chapter 7.5โ˜• 15 min read

Uploading Files & Progress Events

Upload files with progress bars and download files with blob responses. FormData + reportProgress = complete file handling.

01Uploading Files in Angular

Uploading files in Angular uses FormData โ€” the browser's native API for multipart form data.

// Basic upload: FormData + POST
const formData = new FormData();
formData.append('file', selectedFile);
formData.append('name', 'Hyderabadi Biryani');

this.http.post('/api/upload', formData).subscribe(response => {
  console.log('Upload complete:', response);
});

"File upload = parcel bhejna โ€” properly pack karo, phir bhejo."

  • FormData wraps files and text fields into multipart form data
  • POST the FormData to the server endpoint
  • HttpClient automatically sets Content-Type: multipart/form-data with the correct boundary
  • Server must accept multipart/form-data โ€” most backends do
02Creating FormData

FormData is the browser API for creating multipart requests. You append files and text fields.

// HTML
<input type="file" (change)="onFileSelect($event)" multiple accept="image/*" />

// TypeScript
onFileSelect(event: Event) {
  const input = event.target as HTMLInputElement;
  const file = input.files?.[0];
  if (file) {
    this.selectedFile = file;
    this.fileName = file.name;
    this.fileSize = (file.size / 1024).toFixed(2) + ' KB';
  }
}

// Create FormData
const formData = new FormData();
formData.append('file', this.selectedFile);
formData.append('name', 'Hyderabadi Biryani');
formData.append('category', 'chicken');

"FormData = packing box โ€” file daalo, naam daalo, extra info daalo."

Common FormData methods:

  • append(name, value) โ€” add a field or file
  • delete(name) โ€” remove a field
  • get(name) โ€” get a field's value
  • has(name) โ€” check if field exists
  • set(name, value) โ€” replace a field (like append but overwrites)

For multiple files, append the same name multiple times:

for (const file of files) {
  formData.append('photos', file);
}
03Basic File Upload

The simplest upload โ€” just FormData + POST.

import { Component, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-upload',
  standalone: true,
  imports: [FormsModule],
  template: `
    <div class="upload-container">
      <h2>Upload Biryani Photo</h2>

      <input type="file" (change)="onFileSelect($event)" accept="image/*" />

      <div *ngIf="selectedFile" class="file-info">
        <p>๐Ÿ“„ {{ selectedFile.name }}</p>
        <p>Size: {{ (selectedFile.size / 1024).toFixed(1) }} KB</p>
      </div>

      <button (click)="upload()" [disabled]="!selectedFile || uploading">
        {{ uploading ? 'Uploading...' : '๐Ÿ“ค Upload' }}
      </button>
    </div>
  `
})
export class UploadComponent {
  private http = inject(HttpClient);
  selectedFile: File | null = null;
  uploading = false;

  onFileSelect(event: Event) {
    const input = event.target as HTMLInputElement;
    this.selectedFile = input.files?.[0] || null;
  }

  upload() {
    if (!this.selectedFile) return;

    this.uploading = true;
    const formData = new FormData();
    formData.append('file', this.selectedFile);
    formData.append('name', 'Biryani Photo');

    this.http.post('/api/upload', formData).subscribe({
      next: (response) => {
        console.log('Upload successful:', response);
        this.uploading = false;
      },
      error: (error) => {
        console.error('Upload failed:', error);
        this.uploading = false;
      }
    });
  }
}

"Itna simple hai โ€” FormData banao, POST karo, bas."

That's really it. FormData + POST = file upload. Everything else (progress, preview, validation) is extra polish on top.

04Upload with Progress Tracking

Track upload progress with reportProgress: true and observe: 'events'.

import { HttpEventType, HttpEvent } from '@angular/common/http';
import { filter, map } from 'rxjs/operators';

this.http.post('/api/upload', formData, {
  reportProgress: true,    // โ† Enable progress events
  observe: 'events'        // โ† Get all events, not just final response
}).pipe(
  filter(event => event.type === HttpEventType.UploadProgress),
  map(event => ({
    progress: Math.round((event.loaded / event.total!) * 100),
    loaded: event.loaded,
    total: event.total
  }))
).subscribe(progress => {
  this.uploadProgress = progress.progress; // 0 to 100
  this.loadedBytes = progress.loaded;
  this.totalBytes = progress.total;
});

"Progress = Swiggy tracking โ€” kitna percent hua dikhata hai."

Key options:

  • reportProgress: true โ€” emits progress events during upload/download
  • observe: 'events' โ€” returns ALL events (sent, upload progress, response)
  • HttpEventType.UploadProgress โ€” filter for progress events only
  • event.loaded / event.total * 100 โ€” calculate percentage

Progress bar in template:

<div class="progress-bar">
  <div class="progress-fill" [style.width.%]="uploadProgress"></div>
</div>
<p>{{ uploadProgress }}% uploaded</p>
05Downloading Files

Downloading files uses responseType: 'blob' to receive binary data.

downloadFile() {
  this.http.get('/api/export/biryanis', {
    responseType: 'blob'  // โ† Expect binary data, not JSON
  }).subscribe(blob => {
    // Create a URL for the blob
    const url = URL.createObjectURL(blob);

    // Create a temporary anchor to trigger download
    const a = document.createElement('a');
    a.href = url;
    a.download = 'biryani-list.csv';  // Suggested filename
    a.click();

    // Clean up the blob URL to free memory
    URL.revokeObjectURL(url);
  });
}

"Download = reverse upload โ€” server se file laake browser mein save karo."

Key points:

  • responseType: 'blob' โ€” tells Angular not to parse as JSON, keep as binary
  • URL.createObjectURL(blob) โ€” creates a temporary URL pointing to the blob in memory
  • document.createElement('a') + .click() โ€” triggers browser download
  • URL.revokeObjectURL(url) โ€” CRITICAL: releases memory. Blob URLs persist until revoked.

For Excel/PDF downloads, the same pattern works โ€” just set the filename extension correctly.

Key Takeaways

  • โœ… File upload: FormData + POST โ€” HttpClient auto-sets multipart/form-data with boundary
  • โœ… FormData.append(fileName, file) for files, FormData.append(key, value) for text fields
  • โœ… reportProgress: true + observe: 'events' + filter(HttpEventType.UploadProgress) for progress
  • โœ… Download: responseType: 'blob' + URL.createObjectURL() + anchor.click() + URL.revokeObjectURL()
  • โœ… NEVER manually set Content-Type for FormData โ€” HttpClient handles the boundary automatically
Course Search
Search across all chapters & stages
๐Ÿ“–

Search the course

Type any topic โ€” branching, stash, rebase, hooks โ€” and jump straight to that chapter.

merge branchesgit stashundo commitrebase