17

How can I download (.exe file which is in root path) and Upload a file from Angular 4?
I am new to Angular4 and typescript and .NET Core Web API.

I have googled for this but could not find the solution.

Here are some similar questions that I found:

1
  • try with ResponseContentType.Blob function of typescript Commented Oct 10, 2018 at 10:26

7 Answers 7

24

I'd like to add an Angular 4.3/5/6/7/8 update for this especially vis-a-vis the simplified HttpClient. The absence of the 'Content-Type' is especially important since Angular automatically constructs the Content-Type (there is a propensity to add Content-Type=undefined. Don't, as it will create issues under various circumstances and, perhaps, not good practice either). Once there is no Content-Type, the browser will automatically add 'multipart/form-data' and associated parameters. Note, the backend here is Spring Boot although it shouldn't matter.

Here's some pseudo code--please excuse phat fingers. Hope this helps:

MyFileUploadComponent(.html):

...
<input type="file" (change)=fileEvent($event)...>

MyFileUploadComponent(.ts) calls MyFileUploadService(.ts) on fileEvent:

...
public fileEvent($event) {
   const fileSelected: File = $event.target.files[0];
   this.myFileUploadService.uploadFile(fileSelected)
   .subscribe( (response) => {
      console.log('set any success actions...');
      return response;
    },
     (error) => {
       console.log('set any error actions...');
     });
}

MyFileUploadService.ts:

...
public uploadFile(fileToUpload: File) {
  const _formData = new FormData();
  _formData.append('file', fileToUpload, fileToUpload.name);   
  return<any>post(UrlFileUpload, _formData); 
  //note: no HttpHeaders passed as 3rd param to POST!
  //So no Content-Type constructed manually.
  //Angular 4.x-6.x does it automatically.
}
  
Sign up to request clarification or add additional context in comments.

3 Comments

I found this answer the best simple way to accomplish the task.
Hi MoMo thanks for the solution, _formData displaying as empty object. like {}. Please suggest me how to send file to server.
return<any>post() ? Really ?
10

For uploading file, we can post data in form of multipart/form-data. For that, we have to use the FormData class. Here is an example.

Template:

<form #yourForm="ngForm" (ngSubmit)="onSubmit()">
      <input type="text" [(ngModel)]="Name" name="Name"/>
      <input type="file" #fileupload [(ngModel)]="myFile" name="myFile" (change)="fileChange(fileupload.files)"/>
      <button type="submit">Submit</button>
</form>

Component:

import { Http, Response, Headers, RequestOptions } from '@angular/http';
/* When we select file */
Name:string; 
myFile:File; /* property of File type */
fileChange(files: any){
    console.log(files);

    this.myFile = files[0].nativeElement;
}

/* Now send your form using FormData */
onSubmit(): void {
    let _formData = new FormData();
    _formData.append("Name", this.Name);
    _formData.append("MyFile", this.myFile);
    let body = this._formData;
    let headers = new Headers();
    let options = new Options({
        headers: headers
    });
    this._http.post("http://example/api/YourAction", body, options)
      .map((response:Response) => <string>response.json())
      .subscribe((data) => this.message = data);
}

For API to upload file, see this:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-2

2 Comments

I am getting an error in this.myFile = files[0]; as Uncaught (in promise): InvalidStateError: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.
Magic! You use Headers() and Options(). Where are they imported from? Angular? Somewhere else? If Angular, where in Angular? Care to give an all-round answers. Geesh.
2

its very simple component.html will look like

<div class="form-group col-md-6" style="margin-left:50%;margin-top:-8%" >
    <input type="file" value="upload" accept=".jpg" (change)=fileUploader($event)>
</div>

while in the ts file, it will look like

public fileUploader(event) {
    const elem = event.target;
    if (elem.files.length > 0) {
        console.log(elem.files[0]);
    }
    // ...
}

Comments

1
<form [formGroup]="uploadForm" (ngSubmit)="onSubmit()">
    Select image to upload:
    <input type="file" name="avatar" id="fileToUpload" formControlName="file1" (change)="fileEvent($event)">
    <input type="submit" value="Upload Image" name="submit">
</form>
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
@Component({
  selector: 'app-praveen',
  templateUrl: './praveen.component.html',
  styleUrls: ['./praveen.component.css']
})
export class PraveenComponent implements OnInit {

  constructor(private httpClient:HttpClient) { }
    uploadForm = new FormGroup ({
        file1: new FormControl()
    });
    filedata:any;
    fileEvent(e){
        this.filedata=e.target.files[0];
        console.log(e);
    }
    onSubmit() {
        let formdata = new FormData();
        console.log(this.uploadForm)
        formdata.append("avatar",this.filedata);
        this.httpClient
        .post<any>("http://localhost:3040/uploading",formdata)
        .subscribe((res)=>{console.log(res});
    }
  ngOnInit() {
  }

}

1 Comment

It helped me :)
1

to download file with angular try with this, it works`

download(row) {
    return this.Http
      .get(file_path , {
        responseType: ResponseContentType.Blob,
      })
      .map(res => {
        return {
          filename: row.name,
          data: res.blob()
        };
      })
      .subscribe(res => {
        let url = window.URL.createObjectURL(res.data);
        let a = document.createElement('a');
        document.body.appendChild(a);
        a.setAttribute('style', 'display: none');
        a.href = url;
        a.download = res.filename;
        a.click();
        window.URL.revokeObjectURL(url);
        a.remove();
      });
  }

`

Comments

1

Please refer below code for file upload. html code:

<div class="col-md-6">
     <label class="control-heading">Select File</label>
     <input type="file" [multiple]="multiple" #fileInput (change)="selectFile($event)">
     <input type="button" style="margin-top: 15px;" [disabled]="!isUploadEditable" class="data-entry-button btn-pink" (click)="uploadFile()" value="Upload" title="{{globalService.generateTooltip('upload attachment','Click to upload document.')}}" data-html="true" data-toggle="tooltip" data-placement="bottom" />
</div>

Component code:

selectFile(event: any) {
    this.selectedFiles = event.target.files;
}

uploadFile() {
    this.currentFileUpload = this.selectedFiles.item(0);
    this.globalService.pushFileToStorage(this.currentFileUpload).subscribe(event => {
        if (event instanceof HttpResponse) {
            this.loadDocumentInfo();
            this.showNotification('Upload Attachment', 'File Uploaded Successfully', 'success');
            this.myInputVariable.nativeElement.value = "";
        }
    });
    this.selectedFiles = undefined;
}

Global service code:

pushFileToStorage(file: File): Observable<HttpEvent<{}>> {
    const formdata: FormData = new FormData();
    formdata.append('file', file);
    formdata.append('documentVersionId', this.documentVersionId.toString());
    formdata.append('levelId', this.levelId);
    formdata.append('levelKey', this.levelKey);
    formdata.append('LoggedInUser', this.loggedInUser);
    const req = new HttpRequest('POST', this.urlService.CMMService + '/CMMService-service/UploadFileAsAttachment', formdata, {
        reportProgress: true,
        responseType: 'text'
    }
    );
    return this.http.request(req);
}

To download file with file name and file path:

call DownloadFile function from html with filename and filepath as parameters.

component code:

DownloadFile(filePath: string, filename: string) {
    this.globalService.DownloadFile(filePath).subscribe(res => {
        //console.log('start download:', res);
        var url = window.URL.createObjectURL(res);
        var a = document.createElement('a');
        document.body.appendChild(a);
        a.setAttribute('style', 'display: none');
        a.href = url;
        res.filename = filename;
        a.download = res.filename;
        a.click();
        window.URL.revokeObjectURL(url);
        a.remove(); // remove the element
    }, error => {
        console.log('download error:', JSON.stringify(error));
    }, () => {
        console.log('Completed file download.')
    });
}

Global service code to download file:

public DownloadFile(filePath: string): Observable<any> {
   return this.http
        .get(this.urlService.CMMService + '/CMMService-service/DownloadFile?filePath=' + filePath, {
            responseType: 'blob'
        });
}

on server side please use below code:

[HttpGet]
        [ODataRoute("DownloadFile")]
        public HttpResponseMessage DownloadFile(string filePath)
        {
            var fileData = CommonDomain.DownloadFileFromS3(filePath);
            var dataStream = new MemoryStream(fileData.ByteArray);
            HttpResponseMessage httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK);
            httpResponseMessage.Content = new StreamContent(dataStream);
            httpResponseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            httpResponseMessage.Content.Headers.ContentDisposition.FileName = fileData.FileName;
            httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            httpResponseMessage.Content.Headers.Add("x-filename", fileData.FileName);
            return httpResponseMessage;
        }

Please let me know if you guys still facing any issue.

Comments

1

Download any file from the server using Angular 8+ and ASP.NET CORE 2+ version.

Controller implementation to download the file:

    [HttpGet]
        [Route("download")]
        public async Task Download([FromQuery] string file) {
            var uploads = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
            var filePath = Path.Combine(uploads, file);
            if (!System.IO.File.Exists(filePath))
                return NotFound();
    
            var memory = new MemoryStream();
            using (var stream = new FileStream(filePath, FileMode.Open))
            {
                await stream.CopyToAsync(memory);
            }
            memory.Position = 0;
    
            return File(memory, GetContentType(filePath), file); 
        }

Create angular service

    import { Injectable } from '@angular/core';
    import { HttpClient, HttpRequest, HttpEvent, HttpResponse } from '@angular/common/http';
    import { Observable } from 'rxjs';
     
    @Injectable()
    export class DownloadService {
      private baseApiUrl: string;
      private apiDownloadUrl: string;
      private apiUploadUrl: string;
      private apiFileUrl: string;
     
      constructor(private httpClient: HttpClient) {
        this.baseApiUrl = 'http://localhost:5001/api/';
        this.apiDownloadUrl = this.baseApiUrl + 'download';
        this.apiUploadUrl = this.baseApiUrl + 'upload';
        this.apiFileUrl = this.baseApiUrl + 'files';
      }
     
      public downloadFile(file: string): Observable> {
        return this.httpClient.request(new HttpRequest(
          'GET',
          `${this.apiDownloadUrl}?file=${file}`,
          null,
          {
            reportProgress: true,
            responseType: 'blob'
          }));
      }
     }

Create a model in angular

    export interface ProgressStatus {
      status: ProgressStatusEnum;
      percentage?: number;
    }
     
    export enum ProgressStatusEnum {
      START, COMPLETE, IN_PROGRESS, ERROR
    }

Create a component to download a file

    <button
     [disabled]="disabled"
     class="button download"
     [ngClass]="{'disabled': disabled}"
     (click)="download()">download

Create a child component to download a file. Following code in typescript file:

    import { Component, Input, Output, EventEmitter } from '@angular/core';
    import { HttpEventType } from '@angular/common/http';
    import { UploadDownloadService } from 'src/app/services/upload-download.service';
    import { ProgressStatus, ProgressStatusEnum } from 'src/app/models/progress-status.model';
     
    @Component({
      selector: 'app-download',
      templateUrl: 'download.component.html'
    })
     
    export class DownloadComponent {
      @Input() public disabled: boolean;
      @Input() public fileName: string;
      @Output() public downloadStatus: EventEmitter;
     
      constructor(private service: UploadDownloadService) {
        this.downloadStatus = new EventEmitter();
      }
     
      public download() {
        this.downloadStatus.emit( {status: ProgressStatusEnum.START});
        this.service.downloadFile(this.fileName).subscribe(
          data => {
            switch (data.type) {
              case HttpEventType.DownloadProgress:
                this.downloadStatus.emit( {status: ProgressStatusEnum.IN_PROGRESS, percentage: Math.round((data.loaded / data.total) * 100)});
                break;
              case HttpEventType.Response:
                this.downloadStatus.emit( {status: ProgressStatusEnum.COMPLETE});
                const downloadedFile = new Blob([data.body], { type: data.body.type });
                const a = document.createElement('a');
                a.setAttribute('style', 'display:none;');
                document.body.appendChild(a);
                a.download = this.fileName;
                a.href = URL.createObjectURL(downloadedFile);
                a.target = '_blank';
                a.click();
                document.body.removeChild(a);
                break;
            }
          },
          error => {
            this.downloadStatus.emit( {status: ProgressStatusEnum.ERROR});
          }
        );
      }
    }

Add the following implementation in parent component:

    <app-download [disabled]="showProgress" [fileName]="file" (downloadStatus)="downloadStatus($event)">
    <p *ngIf="showProgress"> progress {{percentage}}%

Add the following implementation in parent typescript component:

    import { Component, OnInit } from '@angular/core';
    import { UploadDownloadService } from 'src/app/services/upload-download.service';
    import { ProgressStatusEnum, ProgressStatus } from 'src/app/models/progress-status.model';
     
    @Component({
      selector: 'app-filemanager',
      templateUrl: './file-manager.component.html'
    })
    export class FileManagerComponent implements OnInit {
     
      public files: string[];
      public fileInDownload: string;
      public percentage: number;
      public showProgress: boolean;
      public showDownloadError: boolean;
      public showUploadError: boolean;
     
      constructor(private service: UploadDownloadService) { }
     
      ngOnInit() {
        this.getFiles();
      }
     
      private getFiles() {
        this.service.getFiles().subscribe(
          data => {
            this.files = data;
          }
        );
      }
     
      public downloadStatus(event: ProgressStatus) {
        switch (event.status) {
          case ProgressStatusEnum.START:
            this.showDownloadError = false;
            break;
          case ProgressStatusEnum.IN_PROGRESS:
            this.showProgress = true;
            this.percentage = event.percentage;
            break;
          case ProgressStatusEnum.COMPLETE:
            this.showProgress = false;
            break;
          case ProgressStatusEnum.ERROR:
            this.showProgress = false;
            this.showDownloadError = true;
            break;
        }
      }
    }

DONE!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.