Home » excel » angularjs – [Node][Angular] How to download excel files generated by node

angularjs – [Node][Angular] How to download excel files generated by node

Posted by: admin April 23, 2020 Leave a comment

Questions:

I am currently building a web app in node with angular front end. I want to add an option where the client can download generated excel files. Currently I have some working code that can generate several excel file which are currently stored in a map on the server. What I want is that the user can now download these files and when it is downloaded, the files will be deleted. I don’t know what is best practice for this. Here are some options I have been considering:

  • I will deploy the application on Azure and have the ability to store as blob on Azure. Therefor I could provide an url to download from azure blob directly
  • Maybe I could send the data back as json and let angular generate the excel files?
  • Or I could leave it is at is and let node handle the download?
  • Or something else?

Any suggestions on what I could do and how I can implement it?

Edit: I am generating the excel files with the node package ‘exceljs’

Thanks in advance!

Edit: Thanks to the given answers and a little more googling I have found the answer I was looking for. I have slightly modified it because I am now sending a zip file but it will also work with an excel file.

For sending a zip-file in node:

var archive = archiver.create('zip', {});
archive.pipe(res);
archive.directory(dateDir, name).finalize();

For sending an excel-file in node:

res.setHeader('Content-Type', 'application/vnd.ms-excel');
res.setHeader('Content-disposition', 'attachment; filename=test.xlsx');
workbook.xlsx.write(res).then(function () {
    res.end();
});

For receiving the file in angular I used FileSaver.js as following:

$http({
      url: url,
      method: 'POST',
      headers: headers,
      data: data,
      responseType: 'arraybuffer'
    })
      .success(function (data, status, headers) {
         /*var fileName = headers('Content-Disposition');
         console.log(fileName);*/
        saveAs(new Blob([data], {type: contentType}), 'download.zip');
      })
How to&Answers:

So what you exactly want is that user clicks a button a file gets generated (excel file), and gets downloaded and it doesn’t remain in the server (purely because it doesn’t serve any more purpose)

var path = require('path');
var mime = require('mime');

// write to a file 
var workbook = createAndFillWorkbook();
workbook.xlsx.writeFile(filename)
    .then(function() {
               var file = __dirname + '/upload-folder/<yourfilename>.xlsx';

  var filename = path.basename(file);
  var mimetype = mime.lookup(file);

  res.setHeader('Content-disposition', 'attachment; filename=' + filename);
  res.setHeader('Content-type', mimetype);

  var filestream = fs.createReadStream(file);
  filestream.pipe(res);

  filestream.on('close', function (error) {
    if (err) return res.send(500);
    fs.unlink(__dirname + '/upload-folder/<yourfilename>.xlsx');
  });
});

Here right after the file is created, we pipe the response out to the user, and when stream is closed we are deleting the file, I just wrote the pseudo code

Answer:

Following the solution of @Brij Raj Singh – MSFT, I think you can implement it in the two steps of individual urls for AngularJS.

First step: AngularJS send an http request to URL A for generating that it render data to generate a file, and return back the JSON data include URL B with the generated file name for downloading.

// write to a file 
var workbook = createAndFillWorkbook();
var filename = '<yourfilename>';
// response a url with file name generated
res.write('{"download_url": "/download/"+filename, "name": "XXX"}');

AngularJS render the JSON data received to a link tag <a href="/download/xxx.xlsx">XXX</a>.

Second step: User click the download link and the server send back a file response, then delete the file after downloaded.

var file = __dirname + '/upload-folder/<yourfilename extracted from url>.xlsx';

var filename = path.basename(file);
var mimetype = mime.lookup(file);

res.setHeader('Content-disposition', 'attachment; filename=' + filename);
res.setHeader('Content-type', mimetype);

var filestream = fs.createReadStream(file);
filestream.pipe(res);

filestream.on('close', function (error) {
    if (err) return res.send(500);
    fs.unlink(__dirname + '/upload-folder/<yourfilename>.xlsx');
});

fs.unlink(file);