1

I am trying to create a download button, which enables the user to download a document from my node.js server.

Here's the fancy button:
enter image description here

I am using Angular as a front-end framework and node.js and express.js for the backend.
enter image description here

This is the document I would like the user to be able to download: enter image description here

So for the backend I wrote this code:

server.js

const bodyParser = require('body-parser');
const cors = require('cors')
const express = require('express');
const app = express();
const router = express.Router();
const path = require('path');

app.use(cors());
app.use(bodyParser.json());


router.route('/generateReportByGet').get((req, res) => {
        res.download(path.join(__dirname, 'docs/doc1.txt'), function (err) {
            if (err) {
                console.log(err);
              } else {
                console.log('%c%s', 'color: #f2ceb6', 'NO ERROR');
                console.log('%c%s', 'color: #00a3cc', res);
              }
        });
});

app.use('/', router);
app.listen(5353, () => console.log('Express server running on port 5353'));

After running the server.js file, and typing:

localhost:5353/generateReportByGet

The file gets downloaded:

enter image description here

So here's what my logic told me:

Create a button with Angular that sends a GET request to that same adress and I should get the same result: The file gets downloaded.

So my first question is : Is my logic flawed?

So here's the front-end code:

app.component.html:

<button  color="primary" (click)="generateReportbyGet()">Generate report By Get</button>
<router-outlet></router-outlet>

app.component.ts:

import { Component } from "@angular/core";
import { GenerateReportService } from "./services/generate-report.service";
@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  constructor(private generateReportService: GenerateReportService) {}
  generateReportbyGet() {
    this.generateReportService.generateReportbyGet().subscribe((results) => {
      console.log("generateReportbyGet ...");
      console.log('%c%s', 'color: #aa00ff', results);
  }
}

generate-report.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
  providedIn: 'root'
})
export class GenerateReportService {
  uri = 'http://localhost:5353';
  constructor(private http: HttpClient) {}
  generateReportbyGet() {
    return this.http.get(`${this.uri}/generateReportByGet`, {responseType: 'text'});
  }
}

I thought this should work as I described. However, when I click on the button nothing happens.
But, on the browser console, I am able to retrieve the text from the file:
enter image description here

So here's my second question:
2/ Why doesn't the file downloading process get started when I click on the button? Is it a problem with the code or the GET request logic?
Thank you!!

Akber Iqbal
  • 14,487
  • 12
  • 48
  • 70
Ahmed Ghrib
  • 695
  • 4
  • 13
  • 29

2 Answers2

1

In your Node JS server side code... you're reading the contents of the file and sending them...

(1) to return a file, you can do a:

app.get('/generateReportByGet', function (req, res) { res.sendFile(__dirname + "/" + "docs/doc1.txt"); })

(2) or you can do a (as per this):

app.get('/generateReportByGet', function(req, res){
  const file = `${__dirname}/docs/doc1.txt`;
  res.download(file); 
});
Akber Iqbal
  • 14,487
  • 12
  • 48
  • 70
  • This also worked :D Could you please make a comparison with the other answer ranjeet has provided and tell me which one you think I should use? :D Thank you – Ahmed Ghrib Jun 17 '19 at 12:13
  • 1
    For ranjeet's answer you don't need NodeJS... so if you can construct the full path on client-side, go for it – Akber Iqbal Jun 17 '19 at 12:22
1

File can't be downloaded making ajax call. In your component service change below code.

generateReportbyGet() {
 var link=document.createElement('a');
    link.href=`${this.uri}/generateReportByGet`;
    link.download="MyDoc.txt";
    link.click();
}
ranjeet8082
  • 2,269
  • 1
  • 18
  • 25
  • Problem Solved! Thank you <3 But I want to understand how your solution worked. Can you please provide links or what to search exactly to understand it? I don't just want to copy paste :) – Ahmed Ghrib Jun 17 '19 at 12:08
  • 1
    You can't download it through Ajax because JavaScript cannot save files directly to a user's computer (out of security concerns). For download attribute visit https://webdesign.tutsplus.com/tutorials/quick-tip-using-the-html5-download-attribute--cms-23880 – ranjeet8082 Jun 17 '19 at 12:18
  • Thanks again. Btw, I think this line " link.download="MyDoc.txt"; " is unecessary. – Ahmed Ghrib Jun 17 '19 at 12:29