I was trying to send .xlsx
file using exceljs
and nodejs
to the client as a downloadable file. So far I'm able to create employees.xlsx
file but it's not triggering save file dialog in the browser. Here's what I've tried in my backend API:
My Controller:
exports.exportEmployees = async (req, res) => {
try {
const employees = await Employee.find();
let workbook = new Excel.Workbook();
let worksheet = workbook.addWorksheet("Employees");
worksheet.columns = [
{ header: "Employee Name", key: "fullName", width: 40 },
{ header: "Department", key: "departmentName", width: 25 },
{ header: "Position", key: "positionName", width: 25 },
];
worksheet.addRows(employees);
res.setHeader(
"Content-Type",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
);
res.setHeader("Content-Disposition", "attachment; filename=employees.xlsx");
// This doesn't work either
// workbook.xlsx.write(res).then(function () {
// res.status(200).end();
// });
workbook.xlsx.writeFile("./employees.xlsx").then(
(response) => {
console.log("File is created"); // I'm able to see this in my console
console.log(path.join(__dirname, "../employees.xlsx"));
res.sendFile(path.join(__dirname, "../employees.xlsx"));
},
(err) => {
console.log("ERROR: ", err);
}
);
} catch (err) {
res.status(500).json({ errors: err });
}
};
And in my route.js
router.get("/employee-excel", auth, exportExcelController.exportEmployees);
module.exports = router;
So, the problem I'm facing now is whenever I call the api from my Angular app the browser response is a binary code.
Angular service to call the API
generateEmployeeExcel(query: any): Observable<any> {
return this.http.get(`${this.serverReportAPI}/employee-excel`, {
params: query,
headers: this.tokenHelperService.getAuthToken().headers,
});
}
My component
this.reportService.generateEmployeeExcel(query).subscribe(
(response) => {
console.log("Are we getting here?", response); // not able to get here
this.isLoading = false;
},
(err) => {
console.log("Is there any error?", err); // This is displayed in console
this.isLoading = false;
}
);
Any help would be appreciated.
Change http code to :-
generateEmployeeExcel(query: any): Observable<any> {
return this.http.get(`${this.serverReportAPI}/employee-excel`, {
params: query,
headers: this.tokenHelperService.getAuthToken().headers,
responseType: 'blob'
});
}
For subscribe and download :-
this.reportService.generateEmployeeExcel(query).subscribe(
(res) => {
console.log("Are we getting here?", res); // not able to get here
this.isLoading = false;
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 = "employee.xlsx";
a.click();
window.URL.revokeObjectURL(url);
a.remove();
},
(err) => {
console.log("Is there any error?", err); // This is displayed in console
this.isLoading = false;
}
);
If support for IE is required :-
this.reportService.generateEmployeeExcel(query).subscribe(
(res) => {
console.log("Are we getting here?", res); // not able to get here
if(window.navigator.msSaveBlob) {
window.nagigator.msSaveBlob(res, "employee.xlsx");
return;
}
this.isLoading = false;
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 = "employee.xlsx";
a.click();
window.URL.revokeObjectURL(url);
a.remove();
},
(err) => {
console.log("Is there any error?", err); // This is displayed in console
this.isLoading = false;
}
);