Angular 5 - FileUpload not working - node.js

Edit: Fixed. I had to add this to my response:
.subscribe(data =>{
console.log('data is here: ', data);
});
I have read through whole bunch of articles on this one, but cannot get it to working.
Environment: Angular 5, NodeJS backend with Express. Using Express-FileUpload to upload the file.
I tried my API with this simple HTML:
<html>
<body>
<form ref='uploadForm'
id='uploadForm'
action='http://192.168.1.20:8275/api/upload'
method='post'
encType="multipart/form-data">
<input type="file" name="sampleFile" />
<input type='submit' value='Upload!' />
</form>
</body>
</html>
Figured that my API is working fine, the API End point receives the request from HTML just fine. Now, this is what I am trying to do Angular:
let body = new FormData();
body.append("file", file, 'thefilename');
let options: RequestOptions = new RequestOptions();
options.headers = new Headers();
let response: Observable<Response> = this.http.post('http://192.168.1.20:8275/api/upload', body, options); //code just breaks here and exists silently
response.map(json =>{
console.log('gotcha')
}),err =>{
console.log('error: ', err);
};
Angular code doesn't work. After the POST call, it breaks and exits silently. Nothing in console, no error. And I am unable to figure out why? I read through articles, and found we don't have to supply a content type to make it work. I tried that too but no luck. What can be the issue?

Related

How to convert buffer to file to download on react side

I am using https://www.npmjs.com/package/convert-html-to-pdf to convert html to pdf in nodejs. I have a react frontend and nodejs backend. I want to convert the buffer to a file that people can download on the react side. How can I do this? I don't want to save the file on my servers.
We can set header Content-disposition attachment to indicate that the response is a downloadable file.
Backend: example in Express
const htmlToPDF = new HTMLToPDF(`
<div>Hello world</div>
`);
const buffer = await htmlToPDF.convert();
res.set("Content-Disposition", `attachment; filename="test.pdf"`);
res.set("Content-Type", "application/pdf");
res.send(buffer);
Frontend: example in React
const submit = () => {
window.open("http://localhost:8000"); // Your endpoint here
};
return (
<button onClick={submit}>Download</button>
);
If the endpoint is POST method then window.open won't work. We have to use a form:
<form action="http://localhost:8000" method="POST">
<button type="submit">Download</button>
</form>

How do I serve html,css and js as a post response while using CORS?

Trying to understand the best method to send html,css, js files back to the client via a Post request.
I'm running express,react.
What I have so far is a basic post route, that returns the compiled component with data (using handlebars) as a response. However the event handlers, css and js are absent. I'm not sure how to serve these along with the HTML as a response to an AJAX POST request on another domain.
I'm using webpack for SSR and figured this would work much the same but it doesn't.
Here is what i have so far...this just returns the html from my react component.
app.post("/", async (req, res) => {
const theHtml = `
<html>
<head><title>My First SSR</title>
<link href='http://localhost:8080/app.css'></link>
<script src="http://localhost:8080/app.js" charset="utf-8"></script>
<script src="http://localhost:8080/vendor.js" charset="utf-8"></script>
</head>
<body>
<h1>My First Server Side Render</h1>
<div id="reactele">{{{reactele}}}</div>
</body>
</html>
`;
const hbsTemplate = hbs.compile(theHtml);
const reactComp = renderToString(<App />);
const htmlToSend = hbsTemplate({ reactele: reactComp });
res.send(htmlToSend);
});
The above works and is returned just without js,css event handlers etc..
here is the App component
class App extends React.Component {
constructor() {
super();
this.handleButtonClick = this.handleButtonClick.bind(this);
this.handleTextChange = this.handleTextChange.bind(this);
this.handleReset = this.handleReset.bind(this);
this.state = {
name: "",
msg: ""
};
}
//Handlers
handleButtonClick = e => {
const nameLen = this.state.name.length;
if (nameLen > 0) {
this.setState({
msg: `You name has ${nameLen} characters including space`
});
}
};
handleTextChange = e => {
this.setState({ name: e.target.value });
};
handleReset = () => {
this.setState({ name: "", msg: "" });
};
//End Handlers
render() {
let msg;
if (this.state.msg !== "") {
msg = <p>{this.state.msg}</p>;
} else {
msg = "I have a state of none";
}
return (
//do something here where there is a button that will replace the text
<div>
<header className="App-header">
{/* <img src={logo} className="App-logo" alt="logo" /> */}
{/* <img src={logo} className="App-logo" alt="logo" /> */}
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
<label>Your name </label>
<input
type="text"
id="txtName"
name="txtName"
value={this.state.name}
onChange={this.handleTextChange}
/>
<button id="btnSubmit" onClick={this.handleButtonClick}>
Calculate Name Length
</button>
<button id="btnReset" onClick={this.handleReset}>
Reset All
</button>
<hr />
{msg}
</div>
);
}
}
export default App;
On the client side i'm just appending the html to a blank page.
A few questions,
How do I maintain the eventhandlers on the requested html?
How do send the .css and .js along as well?
For some context, I'd like to avoid having to place and maintain 'client' code on my front-end server? My hope was something like webpack would handle this for me?
Thanks for any tips/suggestions.
EDIT:: To clarify this works if I access the route directly. I get the correlating js and css. Just not via a post request from another domain. I assume I'm missing some fundamental udnerstanding how the dom is maintained and scripts run.
You just need a static directory and a view renderer.
In your app.js or where ever you have initialized your express instance, add the following
var hbs = require('hbs');
var path = require('path');
var express = require('express');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
Now you can just put your html in a hbs file in a folder called 'views' and just return it like
app.post("/", (req, res) => {
res.render('index.hbs', {variable: 'value'});
});
For the static assets add the following lines
app.use(express.static(path.join(__dirname, 'public')));
and put your js and css or images or whatever static files you want in a folder named 'public' in your project root. These will be accessible at http://localhost:8080/app.js
So my issue was on client end (my second domain). It was how i was loading the html into the DOM, my old method was inneHTML on the body. Simple answer is this doesnt work.
I had to load it in another way, I chose to use jquery's .html(), this triggers the dom to evaluate the scripts etc.
#RohithBalaji your comment helped me find my issue.
Most AJAX APIs use the browser's .innerHTML to set the content. And
that will strip the and tags, but the scripts
will execute. But, since the head is stripped I am guessing they
aren't loading?

Send ejs field to a nodejs file

I have the following ejs code.
<form action="/" class = "form-horizontal" method="post">
<textarea class = 'form-control departureCode' name = "departureCode" rows= "1"></textarea>
</form>
This is my post handler code in routes.js file.
routes.post('/', (req, res, next) => {
let departureCode = JSON.parse(req.body.departureCode);
console.log(departureCode);
});
I m not getting this to work successfully. I am getting undefined token error inside my post handler. Could you please help me?
removed JSON.Parse from
let departureCode = JSON.parse(req.body.departureCode);
It worked. Also, made changes suggested by Yogesh Patel in the comments. Thank you all.

What am i missing for the file upload using multipart form data ?

Hi for whatever reason i cannot use packages e.g. multer to upload file to node server. So i found example online, if just upload file in the form, it works fine.
Now i want to send another field "password" together with the file during submit, just cannot make it a work.
I do know there're plenty modules out there, for now just want to this example to work.
<form style="height: 100%;padding-bottom:63px;">
<p>
<input type="file" class="FirmwareFile"
name="myUpload" file-model="upload.newFwFile">
</p>
<p>
<input type="password" name="password" id="password"
placeholder="Password"
ng-model="upload.controllerPassword"
class="formInput">
</p>
</form>
httpSvc.uploadToUrl(myFile, myPd, myServerIPAddress, myRoute) {...}
factory.uploadToUrl = function (fwFile, pd, myServerIp, myRoute) {
var fd = new FormData();
//fd.append('passwd', pd); // cannot pass password to server side ?
fd.append('file', fwFile); // only this works
var deferred = $q.defer();
var completeUrl = ......
$http.post(completeUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).success(function (data) {
deferred.resolve(data);
}).error(function () {
deferred.reject();
});
return deferred.promise;
}
in server side, where to extract the password info please ?
var UploadImage = function(req, res, callback){
var destFile = fs.createWriteStream(uploadDest + "mytest");
var fileSize = req.headers['content-length'];
req.pipe(destFile); //why not sth. like req.body.file.pipe() ?
...
};
Your form does not have
<form enctype="multipart/form-data" action="..." method="...">
...
</form>
You will be better off using node-formidable. The example works straight out of the box. You might also want to look into angularJS specific form upload directives that have been made. No sense in reinventing the wheel.
Cheers

Get ng-model values on POST to Express.js endpoint

I am creating a Node.js application with AngularJS.
I want to make a simple POST, using Angular. This POST should post a couple of values to my server, where I can see them using console.log.
In my HTML code, I build it with the ng-model and a button that has a ng-click.
I can tell my Node.js server is being hit, as it outputs the post called in the console.
However, I have been trying to read about how to read the POST values, but I haven't found a solution.
How would I modify my code to read serialKey and gameTitle in my Express.js endpoint?
My HTML code:
<div class="input-group" ng-controller="CreateController">
<p>Serial key:<br/>
<input class="form-control" ng-model="serialKey" />
</p>
<p>Game:<br/>
<input class="form-control" ng-model="gameTitle" />
</p>
<span class="input-group-btn">
<button class="btn btn-default"
ng-click="postNewIsbn(serialKey,gameTitle)">Add</button>
</span>
</div>
Angular controller code:
app.controller('CreateController',function($scope, $http) {
var url = '/api/serials';
$scope.postNewIsbn = function(serial, game) {
$http.post(url, {
serial: serial,
gametitle: game
})
.success(function (data) {
$scope.data.status = 'success';
})
.error(function(error) {
$scope.data.error = error;
});
};
});
Express.js endpoint
app.post('/api/serials',function(req,res){
console.log(req.body);
console.log('post called');
});
It appears to be the problem of setting content-type header. In your angular application you can set defaultHeaders for your post request just after you initialize the module or in your config function with this line
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
Do remember to inject the $httpProvider dependency whereever you setting this header
UPDATE
It may be the case that you need to configure your express in order to use the bodyParser with this line:
app.use(express.bodyParser());
req.param(name)
When attempting to retrieve data passed with the request, the req.param() function checks the following in order to find the parameter:
req.params
req.body
req.query
See the docs here.
Also, try explicitly setting the content-type header in the POST request to "application/json".

Resources