Receiving req.body empty with post form with Express node.js - forms

I've got a simply form, that sends POST data to my Node.JS server, with Express. This is the form:
<form method="post" action="/sendmessage">
<div class="ui-widget">
<input type="text" id="search" data-provide="typeahead" placeholder="Search..." />
</div>
<textarea id="message"></textarea>
</form>
The ui-widget and the input is releated with typehead, an autocomplete library from Twitter.
And this is how I handle the POST request in the server:
app.post('/sendmessage', function (req, res){
console.log(req.body);
usermodel.findOne({ user: req.session.user }, function (err, auser){
if (err) throw err;
usermodel.findOne({ user: req.body.search }, function (err, user){
if (err) throw err;
var message = new messagemodel({
fromuser: auser._id,
touser: user._id,
message: req.body.message,
status: false
});
message.save(function (err){
if (err) throw err;
res.redirect('/messages')
})
});
});
});
The console shows me '{}', and then an error with req.body.search, because search is not defined. I don't know what is happening here, and it's not a problem related with the typehead input. Any solution for this problem...?
Thank's advance!

req.body is made up of names and values.
add name="search" on your search box and try again.
You also must use the express/connect.bodyParser() middleware, thanks Nick Mitchinson!

I had this problem and it turned out I was using app.use(express.bodyParser()); but it was after the code I was using. Moving it up solved the issue.

on express 4 would be this one. (note that this will not parse multipart/uploads).
app.use(bodyParser.urlencoded({extended: true}));
and if you want to receive json input
app.use(bodyParser.json());

In my case it was caused by my app redirecting http to https.
Updating Facebook to use the https uri fixed it.

In my case I did not provide name tags like this name="firstname" in my input field. After adding them, everything worked.

Related

Getting data from MongoDB with node/express

I have question about getting data form MongoDB with express. I can console.log the correct data, but i'm not able to render it as an .ejs file. It just gives me [object] instead of the actual data. Hope someone can help. I'm very new to express and mongoDB, so it's properly straight forward.
expressApp.get('/home', function(request, response) {
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("agile-app-db");
dbo.collection("Members").findOne({}, function(err, result) {
if (err) throw err;
console.log(result);
response.render('index', {'result' : result})
db.close();
});
});
});
EJS FILE
<ul>
<li><%= result %> </li>
</ul>
Please see Express and ejs <%= to render a JSON
<%- JSON.stringify(result) %>

Ionic 3 Post Request

I'm looking to link my register.html and my register.ts file together for a post request to my back-end. I'm creating a register screen which will send the information to my database (mongoDB/Node)
I started to use [{ngModel}] like in the example below:
<form id="signup-form3">
<ion-list id="signup-list2">
<ion-item id="signup-input6">
<ion-label>
email
</ion-label>
<ion-input type="email" name="email" [(ngModel)]="email" placeholder="Email"></ion-input>
</ion-item>
However kept receiving an error: 'Can't bind to '{ngModel}' since it isn't a known property of 'ion-input'. This was after I put all the necessary imports into my app.module.ts.
In my TS file I'm sending the post request using...
register() {
let headers = new Headers();
headers.append("Content-Type", "application/json");
let body = {
email: "this.email",
password: "this.password"
};
this.http.post('http://localhost:3005/v1/account/register', JSON.stringify(body), {headers: headers})
.map(res => res.json())
.subscribe(data => {
console.log(data);
});
}
Wasn't sure if there was an easier way of going about it or if I'm using ngModel the wrong way.
Edit: Fixed the [(ngModel)] typo. Giving me error now that...
"A user with the given username is already registered" - Which I think it's sending "this.email" to the database - althought when I console log it out, it's showing the email. Is this an issue with the JSON.stringify?
Edit 2 : Getting an error now from my back-end : 'Error: Can't set headers after they are sent.'
The issues is that it's not [{ngModel}], it's [(ngModel)]. That should solve the issue.
EDIT:
Remove the "" from this.email and this.password on the body, should be something like this:
let body = {
email: this.email,
password: this.password
};
Ok I found out the issue with the help of #ChesterLaborde
I had to take out .map(res => res.json())
As #ChesterLaborde mentioned to take out the Stringify - I believe it was because I'm already turning it into JSON, and the .map(res => res.json()) was trying to do it again. I believe this was the root of the problem, worked for me at least.

Sending images with AngularJS and NodeJS

Hi I am making a service to send images with users' information. For example, name, phone number, and their images to upload.
I am planning to use ng-file-upload, one of AngularJS custom dependency. And then, I am going to use Nodemailer to send all the information and images to somewhere else.
But my question is can I send other text data along with ng-file-upload? And second is can I send images with other text data through nodemailer?
Although OP has found a solution in the end, since I had the same problem I figured I'd post the whole code here for others who might struggle with that.
So here is how I combined ng-file-upload and nodemailer to upload and send attachments by e-mail using Gmail:
HTML form:
<form name="postForm" ng-submit="postArt()">
...
<input type="file" ngf-select ng-model="picFile" name="file" ngf-max-size="20MB">
...
</form>
Controller:
app.controller('ArtCtrl', ['$scope', 'Upload', function ($scope, Upload) {
$scope.postArt = function() {
var file = $scope.picFile;
console.log(file);
file.upload = Upload.upload({
url: '/api/newart/',
data: {
username: $scope.username,
email: $scope.email,
comment: $scope.comment,
file: file
}
});
}
}]);
Server:
var nodemailer = require('nodemailer');
var multipartyMiddleware = require('connect-multiparty')();
// multiparty is required to be able to access req.body.files !
app.mailTransporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: ...
pass: ...
},
tls: { rejectUnauthorized: false } // needed or Gmail might block your mails
});
app.post('/api/newart', multipartyMiddleware,function(req,res){
console.log(req.files);
mailOptions = {
from: req.body.email,
to: ...,
subject: ...
text: ...,
attachments: [{
filename: req.files.file.name,
path: req.files.file.path // 'path' will stream from the corresponding path
}]
};
app.mailTransporter.sendMail(mailOptions, function(err) {
if (err) {
console.log(err);
res.status(500).end();
}
console.log('Mail sent successfully');
res.status(200).end()
});
});
The nodemailer examples helped me figure this out!
This works for any file type. The key aspect that some people might miss out is that you need multiparty to access the uploaded file (in req.body.files). Then the most convenient way to attach it is using the path key in the attachment object.
Definitely you can send images as attachment using nodemailer.
Try this for sending image as an attachment :
var mailOptions = {
...
html: 'Embedded image: <img src="cid:unique#kreata.ee"/>',
attachments: [{
filename: 'image.png',
path: '/path/to/file',
cid: 'unique#kreata.ee' //same cid value as in the html img src
}]
}
For more reference on sending image as attachment go through nodemailer's "using Embedded documentation".
For the first part of the question:
Yes! you can send other text data along with image using ng-file-upload. It depends how you want to do it and what you want to achieve.
For example, see the code below:
HTML Template
<form name="form">
<input type="text" ng-model="name" ng-required="true">
<input type="text" ng-model="phoneNo" ng-required="true">
<div class="button" ngf-select ng-model="file" name="file" ngf-pattern="'image/*'" ngf-accept="'image/*'" ngf-max-size="20MB" ngf-min-height="100" ngf-resize="{width: 100, height: 100}">Select</div>
<button type="submit" ng-click="submit()">submit</button>
</form>
Controller
$scope.submit = function() {
if ($scope.form.file.$valid && $scope.file) {
$scope.upload($scope.file);
}
};
// upload on file select or drop
$scope.upload = function (file) {
Upload.upload({
url: 'upload/url',
data: {file: file, 'name': $scope.name, 'phoneNo' : $scope.phoneNo}
}).then(function (resp) {
console.log('Success ' + resp.config.data.file.name + 'uploaded. Response: ' + resp.data);
}, function (resp) {
console.log('Error status: ' + resp.status);
}, function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ' + evt.config.data.file.name);
});
};
Read ng-file-upload documentation completely to see understand all the things you can do along with file upload. It has many examples to make you understand everything.
I hope it helps, and answer your question.

jQuery-File-Upload send error

I want to upload a file as soon as it is added to input. I use code like this
<form>
<input id="MyInput" type="file">
</form>
<script>
$('#MyInput').fileupload({
url: '/Upload',
change: function() {
$('#MyInput').fileupload('send', {})
.success(function() { console.log('success') })
.error(function() { console.log('error') });
}
});
</script>
I see that jQuery-File-Upload send a request with files from the queue and server returns 200 OK. But the promise rejects and I have an 'error' in console.
I look inside the plugin code and see that in this case it returns a promise that always rejects. You should pass a fileInput or files as 'send' parameter to get a resolvable promise. But then files will be duplicated.
How can I get resolved promise with server response?

How to fix TypeError: Cannot read property 'name' from Express Nodemailer

So I do want to say that I've been searching for the answer for this and I've also tried to console.log my req.body post form and I keep getting undefined. So I feel that I'm losing the data from the form I send, I'm not sure what I"m doing wrong. So time to show some code.
As a note: I am using Handlebars for my Express Setup.
app.js
var express = require('express'),
exphbr = require('express3-handlebars'), // "express3-handlebars"
nodemailer = require('nodemailer'),
helpers = require('./lib/helpers'),
app = express(), handlebars;
// Create `ExpressHandlebars` instance with a default layout.
handlebars = exphbr.create({
defaultLayout: 'main',
helpers : helpers,
extname : '.html',
// Uses multiple partials dirs, templates in "shared/templates/" are shared
// with the client-side of the app (see below).
partialsDir: [
'views/shared/',
'views/partials/'
]
});
// Register `hbs` as our view engine using its bound `engine()` function.
app.engine('html', handlebars.engine);
app.set('view engine', 'html');
require("./routes")(app, express, nodemailer);
app.listen(3000);
routes.js
module.exports = function (app, express, nodemailer) {
// set up the routes themselves
app.get('/', function (req, res) {
res.render('home', {
title: 'Larry King Orchestra'
});
});
// I cut out a majority of my routes to make this easier to read.
// SEND EMAIL FROM FORM
app.post('/', function (req, res) {
console.log("WTF");
console.log(req.body.name);
console.log(req.body.email);
var mailOpts, smtpTrans;
//Setup nodemailer transport, I chose gmail. Create an application-specific password to avoid problems.
smtpTrans = nodemailer.createTransport('SMTP', {
service: 'Gmail',
auth: {
user: "email#gmail.com",
pass: "password"
}
});
//Mail options
mailOpts = {
from: req.body.email, //grab form data from the request body object
to: 'anotheremail#gmail.com',
subject: 'LKO Contact Form',
html: 'From: ' + req.body.name + ' <' + req.body.email + '> <br>Phone: ' + req.body.tel + '<br>Date of Event: ' + req.body.date + '<br>Location: ' + req.body.location + '<br>Details & Comments:<br>' + req.body.message + '<br><br><p>Email form provided by WavaMedia.'
};
smtpTrans.sendMail(mailOpts, function (error, response) {
//Email not sent
if (error) {
res.render('home', {
title: 'Larry King Orchestra',
msg: 'Error occured, message not sent.',
err: true,
page: 'home'
});
}
//Yay!! Email sent
else {
res.render('home', {
title: 'Larry King Orchestra',
msg: 'Message sent! Thank you.',
err: false,
page: 'home'
});
}
});
});
// STATIC ROUTE FOR ASSESTS
app.use(express.static('assests/'));
};
I renamed the handlebars extension to be .html and I have the main layout using partials. SO app.get('/') will show this next file as a partial, and render it on the page.
contact.html
<form class="contact" action="/" method="post">
<label for="name">Name</label>
<input type="name" name="name" id="name">
<label for="email">Your Email (required)</label>
<input type="email" name="email" id="email">
<label for="tel">Phone Number</label>
<input type="tel" name="tel" id="tel">
<label for="date">Date of Your Event</label>
<input type="date" name="date" id="date">
<label for="location">Venue/Location</label>
<input type="location" name="location" id="location">
<label for-"message">Details & Comments</label>
<textarea name="message" id="message" rows="3"></textarea>
<input type="submit" name="submit" id="submit" value="Send" class="btn btn-default">
</form>
My Error:
TypeError: Cannot read property 'name' of undefined at c:\xampp\htdocs\lko\routes.js:129:26 at callbacks (c:\xampp\htdocs\lko\node_modules\express\lib\router\index.js:164:37) at param (c:\xampp\htdocs\lko\node_modules\express\lib\router\index.js:138:11) at pass (c:\xampp\htdocs\lko\node_modules\express\lib\router\index.js:145:5) at Router._dispatch (c:\xampp\htdocs\lko\node_modules\express\lib\router\index.js:173:5) at Object.router (c:\xampp\htdocs\lko\node_modules\express\lib\router\index.js:33:10) at next (c:\xampp\htdocs\lko\node_modules\express\node_modules\connect\lib\proto.js:193:15) at Object.expressInit [as handle] (c:\xampp\htdocs\lko\node_modules\express\lib\middleware.js:30:5) at next (c:\xampp\htdocs\lko\node_modules\express\node_modules\connect\lib\proto.js:193:15) at Object.query [as handle] (c:\xampp\htdocs\lko\node_modules\express\node_modules\connect\lib\middleware\query.js:45:5)
So I'm not sure where I'm going wrong with the code. I believe the form is sending data to my node app, but where it's going, I'm not sure. I've setup the post method and so far no luck :( I have been trying for a couple days now. I have nodemailer installed as well. I've restarted the server, updated node and npm.
JavaScript Node Guru Masters, only you can show me the light! And thanks for reading though all of this, totally awesome!
app.use(express.bodyParser());
add that to your app.js
that's what grabs information from the post data form.
You have to require body parser package for this.
At first you have to install it with npm.
$ npm install --save body-parser
Then require that in your js file.
var bodyParser = require('body-parser');
Then add the parser. As you are using html post method it uses urlencoded as encoding type. For that add this line.
var urlencodedParser = bodyParser.urlencoded({ extended: false });
(If you use json you must use bodyParser.json() instead of this)
Now add the parser with the encoding type to app.post method as follows.
app.post('/',urlencodedParser, function (req, res) {
//your code here
});
You don't have to be explicitly mention any bodyParser or bodyParer.json
Instead You can make it simple to use this because this is a built-in middleware function in Express.
app.use(express.json());
app.use(bodyparser.urlencoded({extended : true }));