0

I'm Trying to download to the client an xls file created in the nodejs (using exceljs). The creation is based on http://www.ihamvic.com/2018/07/25/create-and-download-excel-file-in-node-js/

For some reason - I can't save the file in the client - I'm getting "Http failure during parsing for " when subscribing to the getExcel observable. Am I missing some header definition ? See my code:

This is the nodejs side:

const express = require('express');
const router = express.Router();
const excel = require('./excel');

router.use(req, res, next) =>
{
    //The getDataByPromise is a function that return a promise
    return getDataByPromise(req.body.request).then((dataResult) => {
        let reportName = req.body.reportName ? req.body.reportName : '';
        return excel.createExcel(res, dataResult, reportName);
    }).catch((err) => {
        next({
            details: err
        })
    });
})

module.exports = router;

This is the excel module with the createExcel function:

module.exports = 
{
    createExcel : function(res, dataResult, reportTypeName)
    {
        let workbook = new excel.Workbook();
        let worksheet = workbook.addWorksheet('sheet1');
        dataResult.forEach(dataItem => worksheet.addRow(dataItem)); //Insert data into the excel
        
        var tempfile = require('tempfile');
        var tempFilePath = tempfile('.xlsx');
        console.log("tempFilePath : ", tempFilePath);
        workbook.xlsx.writeFile(tempFilePath).then(function() 
        {
            res.sendFile(tempFilePath, function(err)
            {
                if (err)
                {
                    console.log('---------- error downloading file: ', err);
                }
            });
            console.log('file is written');
        });
    }
}

This is the service approaching the nodejs (we'll call it srv) in the client:

getExcel(request : any , reportName : string ) : Observable<any>
{
    var path = <relevant path to the nodejs endpoint>;
    const options = { withCredentials: true };
    
    return this.http.post<any>(path, {request: request, reportName : reportName }, options) //This route to the getDataByPromise function
}

This is the component function:

exportToExcel() : void
{
    this.srv.getExcel(votingBoxRequestForExcel, this.reportTypeNameForExcel).subscribe(result => 
    {
      const data: Blob = new Blob([result], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'});
      
      //FileSaver is file-saver package
      FileSaver.saveAs(data, 'test.xlsx');
    }, 
    error =>  console.log(error) //Reaching to the error instead of the response
  );    
}
double-beep
  • 5,031
  • 17
  • 33
  • 41
Guy E
  • 1,775
  • 2
  • 27
  • 55

2 Answers2

0

Found a solution - I was using wrong method: Instead of using writeFile with a promise and then res.sendFile - I set the header of the response to 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' content type and "Content-Disposition", "attachment; filename=votingboxes.xlsx" and then send using the response sending the workbook "write" method - See corrected code:

res.setHeader('Content-Type', 'application/vnd.openxmlformats- 
officedocument.spreadsheetml.sheet');
    res.setHeader("Content-Disposition", "attachment; filename=votingboxes.xlsx");
    workbook.xlsx.write(res).then(() => 
    {
        res.end();
    })

I'll correct it in the code also

Guy E
  • 1,775
  • 2
  • 27
  • 55
0

You'll need to tell Angular what type of response it can expect, so you can add

responseType

to your http options:

getExcel(request : any , reportName : string ) : Observable<any>
{
    var path = <relevant path to the nodejs endpoint>;
    const options = { withCredentials: true, responseType: 'blob' };

    return this.http.post<any>(path, {request: request, reportName : reportName }, options) //This route to the getDataByPromise function
}
MikeOne
  • 4,789
  • 2
  • 26
  • 23