{"id":12457,"date":"2025-05-30T10:27:47","date_gmt":"2025-05-30T10:27:47","guid":{"rendered":"https:\/\/www.bacancytechnology.com\/qanda\/?p=12457"},"modified":"2025-05-30T10:28:52","modified_gmt":"2025-05-30T10:28:52","slug":"angular-file-upload-with-web-api","status":"publish","type":"post","link":"https:\/\/www.bacancytechnology.com\/qanda\/angular\/angular-file-upload-with-web-api","title":{"rendered":"Angular File Upload with Web API &#8211; Guide for Different Angular Versions"},"content":{"rendered":"<p>This document provides code examples for implementing file upload functionality in Angular applications with a Web API backend, covering different Angular versions.<\/p>\n<h3>HTML Template (Same for all versions)<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\">\r\n<input type=\"file\" (change)=\"onFileSelected($event)\" multiple \/>\r\n<button (click)=\"uploadFiles()\">Upload<\/button>\r\n<progress [value]=\"uploadProgress\" max=\"100\"><\/progress>\r\n<\/pre>\n<h3>Angular 17 (Latest)<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\">\r\n@Component({ standalone: true, imports: [CommonModule] })\r\nexport class FileUploadComponent {\r\n  private http = inject(HttpClient);\r\n  selectedFiles: File[] = [];\r\n  uploadProgress = 0;\r\n\r\n  onFileSelected(event: Event) {\r\n    const input = event.target as HTMLInputElement;\r\n    this.selectedFiles = input.files ? Array.from(input.files) : [];\r\n  }\r\n  uploadFiles() {\r\n    const formData = new FormData();\r\n    this.selectedFiles.forEach(file => formData.append('files', file));\r\n\r\n    this.http.post('\/api\/upload', formData, {\r\n      reportProgress: true,\r\n      observe: 'events'\r\n    }).subscribe({\r\n      next: (event) => {\r\n        if (event.type === HttpEventType.UploadProgress && event.total) {\r\n          this.uploadProgress = Math.round((100 * event.loaded) \/ event.total);\r\n        }\r\n      },\r\n      error: (err) => console.error(err)\r\n    });\r\n  }\r\n}\r\n<\/pre>\n<h3>Angular 15-16<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\">\r\n@Component({ \/* NgModule-based *\/ })\r\nexport class FileUploadComponent {\r\n  constructor(private http: HttpClient) {}\r\n  selectedFiles: File[] = [];\r\n\r\n  onFileSelected(event: any) {\r\n    this.selectedFiles = Array.from(event.target.files);\r\n  }\r\n  uploadFiles() {\r\n    const formData = new FormData();\r\n    this.selectedFiles.forEach(file => formData.append('files', file));\r\n\r\n    this.http.post('\/api\/upload', formData, {\r\n      reportProgress: true,\r\n      observe: 'events'\r\n    }).subscribe({\r\n      next: (event) => { \/* Same as Angular 17 *\/ },\r\n      error: (err) => console.error(err)\r\n    });\r\n  }\r\n}\r\n<\/pre>\n<h3>Angular 12-14<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\">\r\n@Component({ \/* NgModule-based *\/ })\r\nexport class FileUploadComponent {\r\n  constructor(private http: HttpClient) {}\r\n  selectedFiles: FileList | null = null;\r\n  onFileSelected(event: any) {\r\n    this.selectedFiles = event.target.files;\r\n  }\r\n  uploadFiles() {\r\n    if (!this.selectedFiles) return;\r\n    const formData = new FormData();\r\n    Array.from(this.selectedFiles).forEach(file => formData.append('files', file));\r\n\r\n    this.http.post('\/api\/upload', formData, {\r\n      reportProgress: true,\r\n      observe: 'events'\r\n    }).subscribe(\r\n      (event) => { \/* Same progress handling *\/ },\r\n      (err) => console.error(err)\r\n    );\r\n  }\r\n}\r\n<\/pre>\n<h3>Angular 2-11<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\">\r\n@Component({ \/* NgModule-based *\/ })\r\nexport class FileUploadComponent {\r\n  constructor(private http: HttpClient) {}\r\n  selectedFiles: FileList | null = null;\r\n\r\n  onFileSelected(event: any) {\r\n    this.selectedFiles = event.target.files;\r\n  }\r\n  uploadFiles() {\r\n    if (!this.selectedFiles) return;\r\n    const formData = new FormData();\r\n    for (let i = 0; i < this.selectedFiles.length; i++) {\r\n      formData.append('files', this.selectedFiles[i]);\r\n    }\r\n    this.http.post('\/api\/upload', formData, {\r\n      reportProgress: true,\r\n      observe: 'events'\r\n    }).subscribe(\r\n      (event) => { \/* Same progress handling *\/ },\r\n      (err) => console.error(err)\r\n    );\r\n  }\r\n}\r\n<\/pre>\n<h2>Key Differences <\/h2>\n<h3>1. Angular 17 (Latest)<\/h3>\n<ul>\n<li><strong>Standalone Components:<\/strong> No NgModule required. Uses standalone: true.<\/li>\n<li><strong>Modern Injection:<\/strong> inject(HttpClient) replaces constructor-based DI.<\/li>\n<li><strong>Strict Typing:<\/strong> Event targets use type assertions (as HTMLInputElement).<\/li>\n<li><strong>Observable Syntax:<\/strong> Uses subscribe({ next, error }) for cleaner error handling.<\/li>\n<\/ul>\n<h3>Code Impact:<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\">\r\n\/\/ Component definition\r\n@Component({ standalone: true, imports: [CommonModule] })\r\n\r\n\/\/ File selection (strict typing)\r\nonFileSelected(event: Event) {\r\n  const input = event.target as HTMLInputElement;\r\n  this.selectedFiles = input.files ? Array.from(input.files) : [];\r\n}\r\n<\/pre>\n<h3>2. Angular 15-16<\/h3>\n<ul>\n<li><strong>Optional Standalone:<\/strong> Supports both NgModule and (from v15+) standalone.<\/li>\n<li><strong>Improved HTTP Client:<\/strong> Stronger type inference for HttpEventType.<\/li>\n<li><strong>Null Safety:<\/strong> Stricter checks for FileList handling.<\/li>\n<\/ul>\n<h3>Code Impact:<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\">\r\n\/\/ Uses constructor DI (like older versions)\r\nconstructor(private http: HttpClient) {}\r\n\r\n\/\/ FileList conversion (explicit null checks)\r\nif (!event.target.files) return;\r\nthis.selectedFiles = Array.from(event.target.files);\r\n<\/pre>\n<h3>3. Angular 12-14<\/h3>\n<ul>\n<li><strong>Strict Mode Default:<\/strong> Forces null checks (strictTemplates, strictNullChecks).<\/li>\n<li><strong>Ivy Renderer:<\/strong> Better performance but may break legacy View Engine code.<\/li>\n<li><strong>Modern Iteration:<\/strong> Prefers Array.from() over for loops.<\/li>\n<\/ul>\n<h3>Code Impact:<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\">\r\n\/\/ Mandatory null checks\r\nselectedFiles: FileList | null = null;\r\n\r\n\/\/ Safer event handling\r\nif (event.type === HttpEventType.UploadProgress && event.total) { \r\n  \/\/ TypeScript knows `event.total` exists\r\n}\r\n<\/pre>\n<h3>4. Angular 2-11 (Legacy)<\/h3>\n<ul>\n<li><strong>View Engine:<\/strong> Older rendering pipeline (slower, less optimized).<\/li>\n<li><strong>Loose Typing:<\/strong> Frequent use of any for events (event: any).<\/li>\n<li><strong>Manual Checks:<\/strong> No strict mode; runtime errors possible.\n<\/li>\n<\/ul>\n<h3>Code Impact:<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\">\r\n\/\/ Legacy FileList handling\r\nselectedFiles: FileList; \/\/ No strict null checks\r\n\r\n\/\/ Manual type assertions for HTTP progress\r\nif (event.type === HttpEventType.UploadProgress) {\r\n  const progress = (event.loaded \/ (event as any).total) * 100;\r\n}\r\n<\/pre>\n<div class=\"qanda-read-box\"><div class=\"bg-light read-more-icon\"><img decoding=\"async\" src=\"https:\/\/assets.bacancytechnology.com\/qanda\/wp-content\/uploads\/2025\/04\/24061434\/read-txt.png\" alt=\"Also Read\"><p><\/p><h3>Also Read:<\/h3><a href=\"https:\/\/www.bacancytechnology.com\/blog\/angular-hydration\" target=\"_blank\">Angular Hydration<\/a><\/div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>This document provides code examples for implementing file upload functionality in Angular applications with a Web API backend, covering different Angular versions. HTML Template (Same for all versions) Upload Angular 17 (Latest) @Component({ standalone: true, imports: [CommonModule] }) export class FileUploadComponent { private http = inject(HttpClient); selectedFiles: File[] = []; uploadProgress = 0; onFileSelected(event: Event) [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":12458,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[9],"tags":[],"class_list":["post-12457","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-angular"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/posts\/12457"}],"collection":[{"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/comments?post=12457"}],"version-history":[{"count":3,"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/posts\/12457\/revisions"}],"predecessor-version":[{"id":12461,"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/posts\/12457\/revisions\/12461"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/media\/12458"}],"wp:attachment":[{"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/media?parent=12457"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/categories?post=12457"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/tags?post=12457"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}