Using Angular, ExpressJS, NodeJS to download a text Document with a button - javascript

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:
I am using Angular as a front-end framework and node.js and express.js for the backend.
This is the document I would like the user to be able to download:
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:
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:
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!!

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);
});

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();
}

Related

Error On Express Router Setup: Router.use() requires middleware function but got a undefined

I will just say first of all that I am aware of almost all the questions asked on this site under this title.
The solutions there were pretty obvious and already done by me (with no success) or only helped for those specific cases and didn’t really work in my case unfortunately.
Now, for the problem:
I'm trying to create a route that will handle a get request and a post request which are sent to the route 'ellipses'.
These requests should receive and send data from and to an SQL database.
The problem is that for some reason the router is not ready to get these functions and gives me the error in the title:
Router.use () requires middleware function but got an undefined
Here is my code:
This code is from the file dat.js. its porpose is just to access the SQL database.
import { Sequelize } from "sequelize";
export const sequelize = new Sequelize('TheDataBaseName', 'TheUser', 'ThePassword', {
host: 'localhost',
dialect: 'mssql'
});
This code is from the file: controller.js. its porpose is to manage the requests and load the data.
import { sequelize } from "../dat";
export const sendEllipses = async (req, res, next) => {
try {
const ellipses = await getEllipsesFromJson();
return res.send(ellipses);
} catch (e) {
console.log(e);
}
};
export const addNewEllipse = async (req, res, next) => {
const { body: obj } = req;
let newEllipse;
try {
if (Object.keys(obj) !== null) {
logger.info(obj);
newEllipse = await sequelize.query(
`INSERT INTO [armageddon].[dbo].[ellipses] (${Object.keys(
obj
).toString()})
values (${Object.values(obj).toString()})`
);
} else {
console.log("the values are null or are empty");
}
return res.send(newEllipse);
} catch (error) {
console.log(error);
}
};
This code is on the file: routers.js.
its porpose is to define the route
import Router from "express";
import { sendEllipses } from "../ellipses.controller";
import { addNewEllipse } from "../ellipses.controller";
const router = Router();
export default router.route("/ellipses").get(sendEllipses).post(addNewEllipse);
This code is from the file: app.js. This is where everything actually happens.
import { router } from "../routers";
import express from "express";
app.use('/api', router);
app.listen(5000, () => {
console.log("server is runing on port 5000")
});
You need to export the router
const router = Router();
router.route("/ellipses").get(sendEllipses).post(addNewEllipse)
export default router
Now import the router:
import routes from "../router.js";
app.use('/api', routes);
Its also mentioned in the docs: https://expressjs.com/de/guide/routing.html#express-router

Cannot set headers after they are sent to the client error when using the routing-controllers package

I want to use routing-controllers package in my app. But when I add a middleware I get an error.
Here is my code:
index.ts:
import "reflect-metadata";
import { createExpressServer } from "routing-controllers";
import { UserController } from "./UserController";
const app = createExpressServer({
defaultErrorHandler: false,
controllers: [UserController],
});
app.use((req, res, next) => {
res.status(404).send("Not Found!");
});
app.listen(3000, () => {
console.log("********listening**********");
});
UserController.ts:
import { Controller, Get } from "routing-controllers";
#Controller("/users")
export class UserController {
#Get("/")
getAll() {
return "This action returns all users";
}
}
I get "cannot set headers after they are sent to the client error" when I send a request to the "/users/" endpoint. Normally the request finish and the last middleware do not run. Am i wrong?

express.session undefined in typescript

I am very new to typescript/javascript, I am trying to build backend rest apis with session
following is app.ts file
import express from "express";
import { applyMiddleware, applyRoutes } from "./utils";
import routes from "./services";
const app = express();
var ses= {
secret: "secret_session",
resave: true,
saveUninitialized: true,
cookie: { maxAge: 3600000,secure: false, httpOnly: true
}
if (app.get('env') === 'production') {
app.set('trust proxy', 1)
ses.cookie.secure = true
}
app.use(session(ses));
applyRoutes(routes, app);
I have started the server and applied the middlewares for error handling but those are not related to question in my opinion so I'm not adding code for it. Following is my routes.ts code where I'm trying to set the session.
import { Request, Response } from "express";
import { getAll, getByKeyword, addNewProduct } from "./productControllers";
{
path: "/api/v1/getAllProducts",
method: "get",
handler: [
(req: Request, res: Response) => {
getAll()
.then((row: any) => {
var sess = req.session;
sess.views = 1;
res.status(200).json({ data: row });
})
.catch(err => {
res.json({
message: err
});
});
}
]
}
I'm getting error at sess.views = 1;
I have tried the suggested questions before asking it, none of them were of any help to me.
EDIT:
I have created an index.ts
import searchRoutes from "./products/routes";
export default [...searchRoutes];
I have another util class
export const applyRoutes = (routes: Route[], router: Router) => {
for (const route of routes) {
const { method, path, handler } = route;
(router as any)[method](path, handler);
}
}
You are using an interface which is Request for express.js. But it doesn't have type definition for session. So typescript throws a compile error. To solve it you need to define session type under Request interface.
You could define a session.d.ts file under your project. And create required types & interfaces. Like:
declare global {
namespace Express {
interface Request {
session?: Session;
sessionID?: string;
}
}
}
interface Session{
mySessionVarible:string
}
But the good thing is we have DefinitilyTyped project which you can find many type definitions. This needs to solve your compile problem.
npm install --save-dev #types/express-session
And don't forget to change your import for Request.
import { Request, Response } from "#types/express-session";

Meteor JS how to create api for native app?

I am new in meteor js and web app is created in meteor. I need to create API's for mobile app and native and web app
will share the same database. This is not clear to me from where I need to start to create API
for the native app? This is my login route which I am using for the web app.
Path of web app login route
socialapp\socialappv1\app\lib\routes.js
Router.route('login', {
name: 'login',
controller: 'LoginController',
where: 'client'
});
and to create API I have created a server.js file in socialapp\socialappv1\app\server\ directory and I am trying to create API to register a user.
Router.route('/register/',{where: 'server'})
.post(function(){
//console.log(this.request.body);
//return false;
let user = {
email : this.request.body.email,
username : this.request.body.username,
password : this.request.body.password,
};
});
const userId = Accounts.createUser(user);
if(userId)
{
console.log("Register");
}else{
console.log("Not Register");
}
});
Is there any other way to create rest API e.g. to call controllers or is this correct to start API?
I think your code may be trying to set up client side routes (not sure which router you are using).
You need to add server side routes (and you can use express for this), and the handler needs to attach to the Meteor environment
This is some code I have written to handle payment confirmations coming to the server: (server side code of course)
import { Meteor } from 'meteor/meteor'
import express from 'express'
import bodyParser from 'body-parser'
const debug = require('debug')('b2b:server-payments')
async function acceptPayment(req, res) {
// We need to bind to the Meteor environment for this to work.
Meteor.bindEnvironment(() => {
debug('/payment hook', req.body)
try {
// Handle the data that's in req.body ...
:
:
} catch (e) {
console.error(e)
}
})()
res.status(200).json({ status: 'ok' }) // Change this if your data isn't JSON
}
export function setupPaymentsApi() {
debug('Setting up payment hooks')
const app = express()
app.use(bodyParser.json({ extended: false }))
app.post('/payment', acceptPayment)
app.get('/api', (req, res) => {
res.status(200).json({ message: 'B2B Payments API' }) // Shouldn't call this, just for testing for now
})
WebApp.connectHandlers.use(app)
}

getting data from express server with angular 2

I'm trying to build a small facebook login with angular 2 but well I'm having problem, after logging in the facebook the user would be redirected to /home
app.get('/home', function (req, res) {
res.sendfile(path.join(__dirname, '../', 'views', 'index.html'), { user: req.user});
console.log({ user: req.user});
});
I'm trying to display the user information in angular2 page but I keep getting undefined. console logging the object works fine.
I used the same method with ejs files using res.render
and using this inside the ejs
<%= user.facebook.name %>
and it works fine. I tried to use {{}} in the angular 2 but not working.
any help please?
thanks
I would define this element when bootstrapping your application. Because this hint is only available within your index.html page, I would use the following processing.
Update the file that bootstraps your application:
import {bootstrap} from '...';
import {provide} from '...';
import {AppComponent} from '...';
export function main(facebookUser) {
bootstrap(AppComponent, [
provide('user', { useValue: facebookUser })
]);
}
Provide this value from the index.html file this way:
<script>
var facebookUser = '<%= user.facebook.name %>';
System.import('app/main').then((module) => {
module.main(facebookUser);
});
</script>
This question could interest you:
Pass Constant Values to Angular from _layout.cshtml
ok thanks for the replies i found the answer for my question. this code will call the api that and get the user details
constructor(private http: Http) { }
ngOnInit() {
this.getUser();
}
getUser() {
this.http.get('/api/user')
.map((res:Response) => res.json())
.do(data => console.log('data: ' + JSON.stringify(data)))
.subscribe(
data => { this.user = data.user.facebook.name},
err => console.error(err),
() => console.log('done')
);
}

Categories

Resources