[angularjs] how to download file using AngularJS and calling MVC API?

I am using AngularJS, and I have a MVC 4 API that returns a HttpResponseMessage with an attachment.

var result = new MemoryStream(pdfStream, 0, pdfStream.Length) {
     Position = 0
};
var response = new HttpResponseMessage {
     StatusCode = HttpStatusCode.OK,
     Content = new StreamContent(result)
};
response.Content.Headers.ContentDisposition = 
           new ContentDispositionHeaderValue("attachment") {
                    FileName = "MyPdf.pdf"
           };
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return response;

I am using a jQuery plugin called fileDownload... which download the file beautifully... but I havent found the way to do this in the "Angular" way... any help will be appreciated.

// _e

This question is related to angularjs

The answer is


There is angular service written angular file server Uses FileSaver.js and Blob.js

 vm.download = function(text) {
    var data = new Blob([text], { type: 'text/plain;charset=utf-8' });
    FileSaver.saveAs(data, 'text.txt');
  };

This is how I solved this problem

$scope.downloadPDF = function () {
    var link = document.createElement("a");
    link.setAttribute("href",  "path_to_pdf_file/pdf_filename.pdf");
    link.setAttribute("download", "download_name.pdf");
    document.body.appendChild(link); // Required for FF
    link.click(); // This will download the data file named "download_name.pdf"
}

Another example using Blob() Code:

function save(url, params, fileName){
    $http.get(url, {params: params}).success(function(exporter) {
        var blob = new Blob([exporter], {type: "text/plain;charset=utf-8;"});
        saveAs(blob, fileName);
    }).error(function(err) {
        console.log('err', err);
    });
};

// Save as Code
function saveAs(blob, fileName){
    var url = window.URL.createObjectURL(blob);

    var doc = document.createElement("a");
    doc.href = url;
    doc.download = fileName;
    doc.click();
    window.URL.revokeObjectURL(url);
}

per various post... you cannot trigger a download via XHR. I needed to implement condition for the download, so, My solution was:

//make the call to the api with the ID to validate
someResource.get( { id: someId }, function(data) {
     //confirm that the ID is validated
     if (data.isIdConfirmed) {
         //get the token from the validation and issue another call
         //to trigger the download
         window.open('someapi/print/:someId?token='+ data.token);
     }
});

I wish that somehow, or someday the download can be triggered using XHR to avoid the second call. // _e


There is 2 ways to do it in angularjs..

1) By directly redirecting to your service call..

<a href="some/path/to/the/file">clickme</a>

2) By submitting hidden form.

$scope.saveAsPDF = function() {
    var form = document.createElement("form");
    form.setAttribute("action", "some/path/to/the/file");
    form.setAttribute("method", "get");
    form.setAttribute("target", "_blank");

    var hiddenEle1 = document.createElement("input");
    hiddenEle1.setAttribute("type", "hidden");
    hiddenEle1.setAttribute("name", "some");
    hiddenEle1.setAttribute("value", value);

    form.append(hiddenEle1 );

    form.submit();

}

use the hidden element when you have to post some element

<button ng-click="saveAsPDF()">Save As PDF</button>

string trackPathTemp = track.trackPath;

            //The File Path
            var videoFilePath = HttpContext.Current.Server.MapPath("~/" + trackPathTemp);

            var stream = new FileStream(videoFilePath, FileMode.Open, FileAccess.Read);
            var result = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StreamContent(stream)
            };
            result.Content.Headers.ContentType = new MediaTypeHeaderValue("video/mp4");
            result.Content.Headers.ContentRange = new ContentRangeHeaderValue(0, stream.Length);
            // result.Content.Headers.Add("filename", "Video.mp4");
            result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = "Video.mp4"
            };
            return result;

I had the same problem. Solved it by using a javascript library called FileSaver

Just call

saveAs(file, 'filename');

Full http post request:

$http.post('apiUrl', myObject, { responseType: 'arraybuffer' })
  .success(function(data) {
            var file = new Blob([data], { type: 'application/pdf' });
            saveAs(file, 'filename.pdf');
        });

Here you have the angularjs http request to the API that any client will have to do. Just adapt the WS url and params (if you have) to your case. It's a mixture between Naoe's answer and this one:

$http({
    url: '/path/to/your/API',
    method: 'POST',
    params: {},
    headers: {
        'Content-type': 'application/pdf',
    },
    responseType: 'arraybuffer'
}).success(function (data, status, headers, config) {
    // TODO when WS success
    var file = new Blob([data], {
        type: 'application/csv'
    });
    //trick to download store a file having its URL
    var fileURL = URL.createObjectURL(file);
    var a = document.createElement('a');
    a.href = fileURL;
    a.target = '_blank';
    a.download = 'yourfilename.pdf';
    document.body.appendChild(a); //create the link "a"
    a.click(); //click the link "a"
    document.body.removeChild(a); //remove the link "a"
}).error(function (data, status, headers, config) {
    //TODO when WS error
});

Explanation of the code:

  1. Angularjs request a file.pdf at the URL: /path/to/your/API.
  2. Success is received on the response
  3. We execute a trick with JavaScript on the front-end:
    • Create an html link ta: <a>.
    • Click the hyperlink <a> tag, using the JS click() function
  4. Remove the html <a> tag, after its click.

The solution by tremendows worked well for me. However , file was not getting saved in Internet Explorer 10+ also. The below code worked for me for IE browser.

var file = new Blob(([data]), { type: 'application/pdf' });
if (window.navigator.msSaveOrOpenBlob) {
    navigator.msSaveBlob(file, 'fileName.pdf');
}

using FileSaver.js solved my issue thanks for help, below code helped me

'$'

 DownloadClaimForm: function (claim) 
{
 url = baseAddress + "DownLoadFile";
 return  $http.post(baseAddress + "DownLoadFile", claim, {responseType: 'arraybuffer' })
                            .success(function (data) {
                                var file = new Blob([data], { type: 'application/pdf' });
                                saveAs(file, 'Claims.pdf');
                            });


    }