Welcome to our quick Angular file uploads tutorial. You may build a social media platform, collaborative document editing platform, or e-commerce site. Whatever the app you build, we often need to upload files from web clients to our servers. This could be profile pictures, product photos, documents, or any other files.
Today, we’ll look at how we can upload files in Angular. Angular has been there since around 2010. Still, it’s popular among developers, and you can use Angular with the right tools to simplify file uploads and provide a better user experience.
Before we start, feel free to review our HTML File Upload Tutorial to see how basic file uploads are done.
Sending files to the server usually involves sending an HTTP POST multipart request. In a multipart request, the Content-Type header is set to multipart/form-data, and files are delimited by optional boundary parameters. The actual file is sent as a binary block of data.
This differs slightly from a regular REST post request where the Content-Type header is usually set to application/JSON.
Key takeaways
Power for File Uploads in Angular: This tutorial shows how to use Angular’s HttpClient and FormData for a streamlined file upload process, making it easier to integrate file uploads into applications.
Observable-Based File Handling: Observables in Angular manage file upload progress, error handling, and UI updates in real time, providing a smooth user experience.
Backend Setup with Express: Configuring an Express server for file uploads is essential for server-side file management, including handling routes and storage.
Standalone Components in Angular 16: Using standalone components keeps your project modular and organized, which is especially helpful with Angular 16+.
Performance Optimization: Employ lazy loading and code splitting to improve application speed and resource management.
Effective Error Management: Angular and Express make error handling straightforward, ensuring a reliable user experience and easier debugging.
This tutorial covers the essentials for building a scalable, efficient file upload feature in Angular that is suitable for modern web applications.
Let’s dive into the code; we’re starting with a blank angular project with Bootstrap for styling.
Wait! Our output is going to be like this. Awesome, right?
Setting up your Angular file upload project
You’ll need to follow some essential steps to set up your Angular upload file project. You can get started by following these steps in VS Code or any other text editor or IDE.
1. Install Node.js and npm
- You need Node.js and npm (Node Package Manager) for Angular development. Download and install Node.js from nodejs.org.
- Once installed, verify the installation by running the following commands in the VS Code terminal or any other command line interface (CLI) or terminal.
node -v
npm -v
- This will display the installed versions of Node.js and npm.
2. Install Angular CLI
- Angular CLI (Command Line Interface) is a tool that simplifies Angular development. It helps with project setup, development server, and building.
- Install Angular CLI globally using npm:
npm install -g @angular/cli
- If you get any permission issues to install it globally through this command, you can use the command with ‘sudo’ as shown below. It temporarily grants you administrator permissions. You will be prompted to enter your system password to proceed with the installation.
sudo npm install -g @angular/cli
- Use the above option every time when you install a global package if you have a permission issue.
- You can verify the installation by running the following command in your terminal:
ng version
- This will show you the version of Angular CLI and confirm that it’s ready to use.
3. Create a New Angular Project
You can run the following commands in a CLI or terminal to create a new Angular project. I will run them in my VS Code terminal.
- Run this command to create a new Angular project:
ng new file-upload-app
- When prompted:
- Select a stylesheet format (e.g., CSS).
- Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? (y/N) N
- When the project is created, navigate to the project directory.
cd file-upload-app
Note: This Angular single file upload tutorial shows a standalone component-based Angular project (introduced in Angular 16+).
Implementing the single file upload component
Use this command in your terminal to create a new standalone component, ‘single-file-upload,’ in your Angular file upload project.
ng generate component single-file-upload --standalone
This command will add a few files to your Angular project, such as single-file-upload.component.html and single-file-upload.component.ts. We will discuss this in detail in the next sections of this tutorial.
The –standalone flag ensures that it’s created as a standalone component.
Add the following code to the single-file-upload.component.html. It will add a file input field to select the file to upload from your file system, a file details section, an upload button to start the file upload, and a status section to show the file upload progress.
single-file-upload.component.html
<h2>Upload Your File</h2>
<!-- File input field -->
<input type="file" class="upload-input" (change)="handleFileSelection($event)" #fileInput />
<div *ngIf="selectedFile">
<!-- Display file details -->
<section class="file-details">
<h3>Selected File Details:</h3>
<ul>
<li><strong>Filename:</strong> {{selectedFile?.name}}</li>
<li><strong>File Type:</strong> {{selectedFile?.type}}</li>
<li><strong>File Size:</strong> {{selectedFile?.size}} bytes</li>
</ul>
</section>
<!-- Upload button -->
<button (click)="uploadFile()">Start Upload</button>
<!-- Display upload status -->
<section [ngSwitch]="uploadStatus">
<p *ngSwitchCase="'inProgress'">⏳ Uploading, please wait...</p>
<p *ngSwitchCase="'completed'">✅ File uploaded successfully!</p>
<p *ngSwitchCase="'error'">❌ An error occurred during upload.</p>
<p *ngSwitchDefault>🔄 Ready to upload your file.</p>
</section>
</div>
2. Add the associated component logic for handling the upload
Add this code to your single-file-upload.component.ts file in your project to handle the file upload.
single-file-upload.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-single-file-upload',
templateUrl: './single-file-upload.component.html',
styleUrls: ['./single-file-upload.component.css'],
standalone: true, // Ensure standalone mode is enabled
imports: [CommonModule], // Add CommonModule here
})
export class SingleFileUploadComponent {
selectedFile: File | null = null; // Allowing 'null' as an initial value
uploadStatus: string = 'waiting';
handleFileSelection(event: any) {
this.selectedFile = event.target.files[0];
console.log('Selected file:', this.selectedFile);
}
uploadFile() {
if (this.selectedFile) {
this.uploadStatus = 'inProgress';
// Simulate upload with a timeout (replace this with actual upload logic)
setTimeout(() => {
this.uploadStatus = 'completed';
}, 2000);
// Add error handling and actual upload logic as needed
} else {
alert("Please select a file before uploading.");
}
}
}
This code defines the SingleFileUploadComponent class. It allows users to select and upload a single file. Here’s a quick breakdown:
File Selection (handleFileSelection): When a file is selected, the handleFileSelection method is triggered, assigning the chosen file to selectedFile.
File Upload (uploadFile): When the user clicks the upload button:
- It checks if a file has been selected (selectedFiles is not null).
- If a file is selected, it updates the uploadStatus to “inProgress”.
- After a simulated delay (using setTimeout), it updates uploadStatus to “completed” to indicate a successful upload (replace this with actual upload logic in a real app).
- Status Messages: The uploadStatus variable tracks the upload progress (waiting, inProgress, or completed), and the UI can display different messages based on this status.
3. Import the required dependencies in AppComponent
Since we’re using standalone components, we don’t need an app.module.ts file. Instead, we directly import the SingleFileUploadComponent into AppComponent.
Add the below code to app.component.ts:
app.component.ts
import { Component } from '@angular/core';
import { SingleFileUploadComponent } from './single-file-upload/single-file-upload.component';
import { RouterModule } from '@angular/router';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
standalone: true,
imports: [SingleFileUploadComponent, RouterModule] // Import your standalone component here
})
export class AppComponent {
title = 'file-upload-app';
}
4. Adding provideHttpClient() at the application level in main.ts
Adding provideHttpClient() in the main.ts file makes HttpClient available globally, so you don’t need to add it in individual components.
We add provideHttpClient() in Angular applications to enable HTTP client functionality using the HttpClient service, which allows components and services in the app to make HTTP requests to servers.
Your updated main.ts file should look like this:
main.ts
import { provideHttpClient } from '@angular/common/http';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent, {
providers: [provideHttpClient()] // Add HttpClient provider here
}).catch(err => console.error(err));
5. Visualize the SingleFileUploadComponent
We need to add the SingleFileUploadComponent selector inside the src/app/app.component.html file to visualize it inside the main AppComponent.
To embed the component, you can simply add this selector tag to the app.component.html file.
app.component.html
<!-- Other HTML →
<h1>Welcome to the File Upload App</h1>
<!-- Embedding the Single File Upload Component -->
<app-single-file-upload></app-single-file-upload>
<!-- Other HTML -->
6. Run the project
Go to your terminal and execute the following command in your project’s root directory.
ng serve
Then, you can access your application at http://localhost:4200 through your browser.
The result should look something like this:
When you choose a single file from your file system and upload it, this application will simulate the file uploading process and show you the below output screen.
By the way, we still need to implement the actual file-uploading functionality. To do this, we need to use the FormData and Angular’s HTTP client capabilities.
7. Create a service for the network calls
This service actually takes care of the upload process.
To do this, follow the below steps to create the upload.service.ts file. This service will handle the actual file upload logic by sending an HTTP POST request to the server.
- Navigate to the src/app directory: If you use VS Code, open your Angular project and go to the src/app folder.
- Create a new folder named services.
- Create the upload.service.ts file inside the services folder.
- Paste the service code into the upload.service.ts file:
upload.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class UploadService {
private uploadUrl = 'http://localhost:3000/uploadFile'; // Replace with your backend URL
constructor(private httpClient: HttpClient) {}
uploadFile(file: File): Observable<any> {
const formData = new FormData();
formData.append('file', file);
return this.httpClient.post(this.uploadUrl, formData);
}
}
Here, we’re making a post request to our backend operating on http://localhost:3000 to the path of /uploadFile path.
FormData is not an angular-specific component; it also represents an HTTP form submission in Vanilla Js. The Angular HttpClient accepts this as a valid argument for the body of the HTTP request.
8. Replace the file upload simulation in the component with the actual logic
Now, we have to replace the file-uploading simulation in the single-file-upload.component.ts file with the actual logic.
Replace this code:
With this:
Here’s the updated single-file-upload.component.ts file.
single-file-upload.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { UploadService } from '../services/upload.service'; // Import the UploadService
@Component({
selector: 'app-single-file-upload',
templateUrl: './single-file-upload.component.html',
styleUrls: ['./single-file-upload.component.css'],
standalone: true, // Ensure standalone mode is enabled
imports: [CommonModule], // Add CommonModule here
})
export class SingleFileUploadComponent {
selectedFile: File | null = null; // Allowing 'null' as an initial value
uploadStatus: string = 'waiting';
constructor(private uploadService: UploadService) {}
handleFileSelection(event: any) {
this.selectedFile = event.target.files[0];
console.log('Selected file:', this.selectedFile);
}
uploadFile() {
if (this.selectedFile) {
this.uploadStatus = 'inProgress';
this.uploadService.uploadFile(this.selectedFile).subscribe({
next: () => {
this.uploadStatus = 'completed';
},
error: () => {
this.uploadStatus = 'error';
}
});
} else {
alert("Please select a file before uploading.");
}
}
}
9. How to set up a basic server to handle file uploads
We need a backend server to handle the file uploads. Let’s set up a backend server running at http://localhost:3000/uploadFile to handle the file upload in this example. The UploadService method in Angular sends a POST request to this endpoint, expecting the server to process the uploaded file.
Here’s a simple guide on how to set up a basic server to handle file uploads:
Step 1: Choose a backend framework
We can use a backend framework like Node.js with Express. Let’s set it up.
Step 2: Install Node.js and Express
If you haven’t already installed Node.js, download it from Node.js official website. Then, create a new folder for your backend server, navigate to it in the terminal, and initialize a new Node.js project:
mkdir backend
cd backend
npm init -y
Install Express and multer (a middleware for handling file uploads in Node.js):
npm install express multer
Step 3: Set up the server
In your backend folder, create an index.js file and add the following code:
const express = require('express');
const multer = require('multer');
const cors = require('cors');
const fs = require('fs');
const app = express();
const PORT = 3000;
// Enable CORS for Angular
app.use(cors());
// Create upload directory if it doesn't exist
const uploadDir = 'uploads';
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir);
}
// Set up multer for file upload
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/'); // Upload directory
},
filename: function (req, file, cb) {
cb(null, file.originalname); // Keep the original file name
}
});
const upload = multer({ storage: storage });
// Define upload route
app.post('/uploadFile', (req, res) => {
upload.single('file')(req, res, function (err) {
if (err instanceof multer.MulterError) {
return res.status(500).json({ message: 'Multer error occurred during upload.', error: err.message });
} else if (err) {
return res.status(500).json({ message: 'An unknown error occurred during upload.', error: err.message });
}
if (!req.file) {
return res.status(400).json({ message: 'No file uploaded.' });
}
console.log('File uploaded successfully:', req.file);
res.status(200).json({ message: 'File uploaded successfully.' });
});
});
// Serve uploaded files (optional)
app.use('/uploads', express.static('uploads'));
// Start the server
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
Step 4: Run the Server
Navigate to your backend folder in a new terminal and run:
node index.js
This will start your backend Express server on http://localhost:3000 (as specified in your index.js file). Now, your backend is ready to handle the file upload.
10. Re-run your Angular frontend app
Go to a different terminal and execute the following command in your project’s root directory again.
ng serve
Then, you can access your application at http://localhost:4200 through your browser again.
Choose a file:
And upload it:
You can see the successful message when the file upload process is successfully handled in your front end and the back end. You can also see the uploaded file in the uploads directory inside your backend directory.
Get the complete code from this GitHub repository.
You can also see how to receive and parse the file from the body of the request on a NodeJs server running expressJs in our NodeJS tutorial.
When embarking on implementing file uploads in Angular, there are a few key points to think about. Delving into additional major and minor concepts can significantly enhance your understanding and capabilities. These concepts not only expand your knowledge but also empower you to create more efficient, user-friendly, and optimized file upload functionalities within your Angular applications. Let’s explore these concepts in greater detail to ensure your file upload implementation is robust, responsive, and aligned with best practices.
Uploading Files with Observables
Angular’s focus on reactive programming is a powerful paradigm for managing asynchronous operations. In the context of file uploads, leveraging observables enhances the application’s responsiveness and maintainability.
Reactive Event Handling
Reactive programming using observables allows for elegant event handling and data flow management. Instead of traditional imperative event listeners, the (change) event for file selection in the article’s tutorial can be transformed into an observable stream. This enables developers to apply various operators, such as debounceTime or switchMap, to control the timing and sequencing of events. Reactive event handling ensures efficient utilization of resources and a more streamlined user experience during file uploads.
Progress Tracking and Error Handling with Observables
Observables extend beyond basic event handling by enabling comprehensive progress tracking and error handling during file uploads. By wrapping the HTTP request in an observable, developers can subscribe to events that provide updates on upload progress. This allows for real-time feedback to users through progress bars or notifications. Furthermore, observables make it convenient to handle errors by using the catchError operator to gracefully manage failed uploads and provide meaningful error messages to users.
Optimizing Performance with Lazy Loading and Code Splitting
As Angular applications grow in complexity, optimizing performance becomes crucial. Lazy loading and code splitting are strategies that significantly improve loading times and resource usage, especially in scenarios involving file uploads.
Lazy Loading Modules
Angular’s lazy loading enables the loading of specific modules only when they are needed. In the context of file uploads, this means that the components and services related to uploading files can be encapsulated within a separate module. By doing so, these resources are loaded on demand, reducing the initial load time of the application. Lazy loading modules also contribute to more efficient memory usage as resources are allocated only when required.
Code Splitting for Smaller Bundles
Code splitting is closely related to lazy loading and involves breaking down the application’s codebase into smaller, manageable chunks or bundles. When a user accesses a specific feature, only the relevant bundle is loaded, leading to faster initial loading times. In the context of file uploads, code splitting ensures that the components and services associated with file handling are isolated from other parts of the application, resulting in a more optimized and responsive user experience.
And there you have it! Your very own file upload tool for your Angular applications. If you’re planning to make one that’s specific to images, then check out this Angular image uploader API tutorial.
Conclusion
In conclusion, building a file upload feature in Angular involves a combination of Angular’s HttpClient, observables, and FormData, creating a seamless process for users. By setting up a basic Express server, you can efficiently manage uploaded files on the backend. Angular’s reactive programming capabilities also allow for real-time feedback, enhancing the user experience. This tutorial equips you with the essentials to implement and customize file uploads for various applications, whether for profile photos, documents, or other file types. With these concepts in mind, you’re ready to integrate robust, user-friendly file upload functionality into your Angular projects.
Product Marketing Manager for Filestack. A technology enthusiast at heart.
Read More →