Handle downloads with Angular

In this tip, we will describe how to handle downloads with Angular with both a link and from AJAX calls.

Trigger a download on a link

This is the classical way to trigger a download. The user clicks on a link and the server sends appropriate HTTP headers to tell the browser that it must trigger a download. Nothing specific here to the JS application running in the browser. We can however notice that such approach necessarily uses a HTTP GET method.

The header involved is ContentDisposition. When the browser detects it in the response, it triggers download and opens a popup dialog. The header allows to specify the name of the file corresponding to the sent content.

Below is a sample of the returned content that triggers a download in the browser:

  • Header Content-Type: application/zip
  • Header Content-Disposition: filename; filename=myzipfile.zip
  • Header Transfer-Encoding: chunked

Handle download on AJAX calls with Angular

HTML5 provides a solution to emulate the previous behavior but following an AJAX request. The latter returns in its payload the content to download. The call can use any method that can return a content. This corresponds to processings as shown below:

var url = (...)
var expectedMediaType = (...)

var requestData = (...)
$http.post(url, requestData, {
    params: {
        queryParam: 'queryParamValue'
    },
    headers: {
        'Content-Type': 'application/json',
        'Accept': expectedMediaType
    }
}).then(function (response) {
    (...)
});

FileSaver.js implements the HTML5 W3C saveAs() FileSaver interface in browsers that do not natively support it. The library is the solution to saving files on the client-side, and is perfect for webapps that need to generate files. It can be reached at thr address: (https://github.com/eligrey/FileSaver.js)[https://github.com/eligrey/FileSaver.js]. To install it, just reference its js file using a tag script in your HTML page.

<script src="js/FileSaver.js"></script>

This provides to your script the js function saveAs. Following code describes how to use to display a popup dialog to save content (binary or not):

function openSaveAsDialog(filename, content, mediaType) {
    var blob = new Blob([content], {type: mediaType});
    saveAs(blob, filename);
}

Following code describes how to connect the AJAX request and the save as processing:

var url = (...)
var expectedMediaType = (...)

var requestData = (...)
$http.post(url, requestData, {
    params: {
        queryParam: 'queryParamValue'
    },
    headers: {
        'Content-Type': 'application/json',
        'Accept': expectedMediaType
    }
}).then(function (response) {
    var filename = (...)
    openSaveAsDialog(filename, response.data, expectedMediaType);
});

Handling different content types with Angular

When receiving JSON content, Angular automatically convert it as JSON object from the text content. We need to transform this object as string to provide it as download:

var requestData = (...)
$http.post(url, requestData, {
    (...)
}).then(function (response) {
    var textContent = JSON.stringify(response.data, null, '\t');
    var filename = (...)
    openSaveAsDialog(filename, response.data, expectedMediaType);
});

When testing with binary content like zip files or images, we see that the downloaded content is corrupted. This is due to the fact that Angular automatically applies transformation on the received data. When handling binary contents, we want to get them as array buffer. To do this, we can leverage the parameter responseType of methods of the object $http. Following code describes how to use it:

var responseType = 'arraybuffer';

var requestData = (...)
$http.post(url, requestData, {
    (...)
}, responseType: responseType).then(function (response) {
    var filename = (...)
    openSaveAsDialog(filename, response.data, expectedMediaType);
});

Advertisements
This entry was posted in Angular, Tips and tagged , . Bookmark the permalink.

2 Responses to Handle downloads with Angular

  1. zuzik says:

    Thank you for “var responseType = ‘arraybuffer’;”

  2. twoyao says:

    Thank you for “var responseType = ‘arraybuffer’;” . It helps

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s