callback in multiparty form parsing is not executed, seems (express 3) - node.js

I am learning to handle file upload in express 3.
module.exports.upload is my route handler for POST request to '/image/upload' :
var multiparty = require('multiparty');
module.exports.uploadPage = function (req, res) {
res.render('image/image', {file_content: null });
}
module.exports.upload = function (req, res) {
var form = new multiparty.Form();
form.parse(req, function(err, fields, files){
console.log('inside form parsing call back');
res.writeHead(200, {'content-type': 'text/plain'});
res.end('received upload:\n\n');
});
if(req.method == 'GET') res.render('image/image');
}
this is my form:
<form action="/image/upload" enctype="multipart/form-data" method="post">
<input type="file" name="thumbnail" multiple="multiple" />
<input type="submit"/>
</form>
the console.log('inside form parsing call back'); is never executed since nothing is logged in terminal. I am using dev setting, the POST request log is even not logged to console.
Btw, I compared my code with example here. I beleive I am doing it right, but I can be wrong.
The callback seems not to be executed in this situation. Where went wrong?
Thank you!

Let me answer my question. The above code is good, but the reason it doesn't work is because I added
app.use(express.multipart());
in app.js
then add
var multiparty = require('multiparty');
again in the controller, which is image.js
This may not be helpful to you, but the take away is that only load(require(...)) multiparty where it needs to process forms. Don't use app.use, use require as this document suggests:
multiparty on github

Related

How to access body parameters while using multipart form data in NodeJS

There were lots of similar questions related to mine, but no one gonna clear my doubt.
So,whenever I write
<form id="form" action="/" method="post" role="form">
and in my backend code, Let say I write
console.log(req.body.name)
I got the data correctly, but if I add enctype = multipart/form-data as
<form id="form" action="/" method="post" role="form" enctype="multipart/form-data">
I got req.body.name as 'undefined' or body parameters as 'undefined'.
Is there any way to get the body parameters While using enctype="multipart/form-data?
Please Help!
enctype="multipart/form-data" is not natively handled by express, you can use multer to handle multipart/form-data
npm install --save multer
Multer NPM
const multer = require('multer');
let upload = multer({ dest: 'uploads/' }); //<-- Could be any folder
router.post('/', upload, function (req, res) {
console.log('Body- ' + JSON.stringify(req.body));
});
In an alternative way, you can use a formidable module from the NPM.
Npm formidable
npm install --save formidable
const multer = require('formidable');
router.post('/', upload, function (req, res) {
const form = formidable({ multiples: true });
form.parse(req, (err, fields, files) => {
console.log('fields: ', fields);
console.log('files: ', files);
// enter code here
});
});

Form Data being posted twice via XMLHttpRequest, once as an empty object and once with the correct data

I am learning web development and in that, AJAX. For this particular example I am using the XMLHttpRequest object on the browser and Node with Express as my server.
I have a simple HTML form that needs to post data to a Node server. I know that data is being posted successfully, because, I can see the Form Data in the chrome's Network tab.
I have a couple of problems with my code and I've looked for answers on Stackoverflow and also looked at the MDN documentation for the past three days, but am unable to figure this.
The questions below are with respect to the posted code:
If submitForm() returns true, I have the data posted twice to the server, once with an empty request body and once with the expected data. Why?
Post Data when submitForm() returns true
If submitForm() returns false, no data is posted back to the server. Why?
Post Data when submitForm() returns false
If there is no call to submitForm() at all (ie. sans a call to XHR), then the form data is posted correctly and this is seen in the req.body on the server side.
Result of POST when there is no onSubmit event attached to the form
If I set the RequestHeader on xhr to application/x-www-form-urlencoded, this is what I get.
How do I get the form to post data to the server using XMLHTTPRequest?
I am completely lost and am not sure what I am missing. If someone can throw some light, I would appreciate that greatly.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge, chrome=1"/>
<script>
"use strict";
function submitForm()
{
var formElement = document.getElementById("myForm");
var formData = new FormData(formElement);
var xhr = new XMLHttpRequest();
xhr.open("POST", "/Test", true);
xhr.send(formData);
//return false;
}
</script>
</head>
<body>
<form id="myForm" method="POST" action="/Test" onsubmit="return submitForm();" >
<input type="text" value="John" name="name"/>
<input type="submit" value="Send Data"/>
</form>
</body>
</html>
//Server side code (NodeJS)
var express = require('express');
var bodyparser = require('body-parser');
var app = express();
app.use(express.static('./'));
var urlencoded = bodyparser.urlencoded({extended:true});
app.get('/Test', function(req, res){
res.sendFile(__dirname+'/Test.html');
});
app.post('/Test', urlencoded, function(req, res){
console.log("In POST");
console.log(req.body);
res.sendFile(__dirname+'/Test.html');
});
app.listen(8080);
console.log('Now listening on port 8080...');
after looking through your code and testing it out myself. I found out that...
To answer the first question, you are actually submitting the data "John" twice. The first time was through your "submitForm()" function. The second time was through the element attributes method="POST", action="/Test".
The submitForm function is actually working but you are using XMLHttpRequest() to send the post request to the server. If you read the documentation, XMLHttpRequest uses multipart/form-data enctype to send the form data. Therefore your route must be able to handle multipart/form-data format.
To find out if your submitForm() function is indeed called, you could always add a alert(' into the function. If it is called, a prompt will pop up. Always a great way to debug!
Format sent by XMLHttpRequest(): multipart/form-data, format handled: urlencoded, a bit of a mismatch here
Finally let's get to the solution. Like I said your route needs to be able to handle multipart/form-data.
var express = require('express');// I have no idea why I couldn't format this line to code :/
var bodyparser = require('body-parser');
var multer = require('multer') // Use this module to add a middleware onto your route
var mult_handler = multer() // creates a handler object
var app = express();
app.use(express.static('./'));
var urlencoded = bodyparser.urlencoded({extended:true});
app.get('/Test', function(req, res){
res.sendFile(__dirname+'/Test.html');
});
app.post('/Test', mult_handler.none(), function(req, res){
console.log("In POST");
console.log(req.body);
res.sendFile(__dirname+'/Test.html');
});
app.listen(8080);
console.log('Now listening on port 8080...');

NodeJS (Express) - app.delete route not working

Working on understanding CRUD basics with setting up simple routes from my HTML5 doc to Postgres database. My GET and POST buttons are working but my DELETE is not deleting from my database. I realize the routes all look very similar (and tried renaming them to see if it would hit the callback function that is linked to the database, but it didn't work). Can anyone tell me why my HTML5 form is not working with my route to reach the database for DELETE? Thanks!
I will only include the code I'm referring to as I have all the other code working well. Starting with showing the crappy HTML first, then the index.js with the routes, and then the queries.js with the database queries. ( ////// seperate the documents where the code is pulled :) )
<h1>Let's DELETE ONE Human</h1>
<form action="/users/:id" method="delete">
ID:<input type="number" name="id">
<input type="submit" name="">
</form>
/////////////////////////////////////////////////////////////////
app.get('/', (request, response) => {
response.sendFile(path.join(__dirname + '/html/homepage.html'))
}, db.getUsers)
app.get('/newHuman.html', (request, response) => {
response.sendFile(path.join(__dirname + '/html/newHuman.html'))
})
app.get('/users', db.getUsers)
app.get('/users/:id', db.getUserById)
app.post('/users', db.createUser)
app.put('/users/:id', db.updateUser)
app.delete('/users/:id', db.deleteUser)
app.listen(port, () => {
console.log(`App running on port ${port}.`)
})
////////////////////////////////////////////////////////////////////////
const deleteUser = (request, response) => {
const id = parseInt(request.query.id)
pool.query('DELETE FROM users WHERE id = $1', [id], (error, results) => {
if (error) {
throw error
}
response.status(200).send(`User deleted with ID: ${id}`)
})
}
TL;DR
How can I send to the correct route (even with just POSTing twice) from my HTML when the app.delete and app.put have the exact same route? Tried renaming route, didn't work but I know you shouldn't have to rename for it to work. Here are routes:
app.put('/users/:id', db.updateUser)
app.delete('/users/:id', db.deleteUser)
HTML form method only supports GET and POST method.
Either you have to use GET or POST or you can use ajax or some library like request or axios to make the DELETE request.
For example, if you use axios, try the following code.
Ignore importing jQuery and axios, if you already imported them.
<!-- import jQuery -->
<script
src="https://code.jquery.com/jquery-3.3.1.js"
integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60="
crossorigin="anonymous"></script>
<!-- import axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<h1>Let's DELETE ONE Human</h1>
<form id='myFormId' action="/users/:id" method="delete">
ID:<input type="number" name="id" id='deleteId'>
<input type="submit" name="">
</form>
<script>
$( document ).ready(function() {
const myForm = $('#myFormId');
myForm.submit((event) => {
event.preventDefault();
const id = $('#deleteId').val();
const url = `/users/${id}`;
axios.delete(url)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
});
});
</script>
Another easier way of doing this is using a npm module called method-override.
In your main entry point file for your server, add the following lines:
const express = require('express');
const app = express();
const methodOverride = require('method-override');
app.use(methodOverride('_method'));
In your HTML form, you can now use PUT or DELETE requests easily:
For example:
<h1>Let's DELETE ONE Human</h1>
<form id='myFormId' action="/users/:id?_method=DELETE" method="delete">
ID:<input type="number" name="id" id='deleteId'>
<input type="submit" name="">
</form>
Notice the action attribute of the form, all you have to do now is add that simple line and you are done!

call node function, from ejs form

I'm making a node application where I need to call a function, written inside my app.js, and I need to call it from, a form, in a template, made with ejs.
i'm using node.js, express.js and ejs.
can anyone help?
You want to use ajax to interface with the server-side function:
$.get('/your_route', {data: 'goes here'}, function (res) {
console.log('callback after your node function is done')
})
You might call the function from the template by:
<form class="ajax_caller" onsubmit="do_ajax_call()">form goes here</form>
However that is not considered a good practice. This is much better:
// click event
$(document).on('submit', 'form.ajax_caller', do_ajax_call)
function do_ajax_call (e) {
e.preventDefault()
$.get('/your_route', {data: 'goes here'}, function (res) {
console.log('callback after your node function is done')
})
}
Ofcourse you will have to set up a route in express:
app.get('/your_route', function (req, res) {
finally_your_function()
res.send('finished')
});
If you don't want to use ajax, you can just set the action of the form to your ajax route, however that will redirect user to the route so you will have to handle that.
You can use regular HTML forms which submit their content to a certain URL on the server.
Example:
Add the form to HTML/EJS:
<form method="GET" action="/sampleUrl">
<input type="submit" name="submit">
</form>
Add the route to your app.js:
var express = require('express');
var app = express();
app.get('/sampleUrl', function(req, res) {
//Do something
});

Form Data is correct when POSTing in Angular, but req.body is empty in node?

I am trying to do a simple POST call to a RESTful API that I created. I am using Angular for the client-side, nodejs for the server, and mongodb+express+multer for the database.
When testing the back-end using POSTman, the objects are created correctly, getting data from the req.body. In my Angular controller's createProject method, I am printing out my formData right before POSTing to the API. The form data looks correct. When the correct form data is POSTed to the working server, the req.body shows up empty.
Here is my relevant server code:
app.use(express.static(__dirname + '/public'));
app.use(multer({ dest: 'public/uploads/'}));
router.route('/projects') // accessed at //localhost:8080/api/projects
.post(function(req, res) {
console.log(req.body); // returns empty set
var project = new Project();
project.name = req.body.name;
project.description = req.body.description;
project.newComments = 0;
project.newPosts = 0;
//project.imageURL = req.body.imageURL;
project.save(function(err) {
if (err)
res.send(err);
Project.find(function(err, projects) {
if (err) res.send(err);
res.json(projects);
});
});
})
app.use('/api', router);
Here is my relevant Angular code:
$scope.createProject = function() {
console.log($scope.formData); // returns correct **{name: "adawda", description: "dawdaw"} **
$http.post('/api/projects', $scope.formData)
.success(function(projectData) {
$scope.formData = {};
$scope.imageURL = "";
$scope.projects = projectData;
console.log(projectData);
})
.error(function(projectData) {
console.log('Error: ' + projectData);
});
};
Here is my relevant HTML code:
<input type="text" placeholder="name of project" ng-model="formData.name" />
<input type="text" placeholder="description" ng-model="formData.description" />
<button type="submit" class="button" ng-click="createProject()">Create Project</button>
The Question:
How does Angular pass data from the $scope.formData to the request, and why is it not compatible with my server configuration? I'm pretty sure it has to do with the content-type in my POST, and how that relates to multer.
Thanks for your time!
You can use body parser middleware
app.use(bodyParser());

Resources