I want to upload image using a jade form then i want to show it in a posts page the problem is the images are uploaded as files with no extension and then i get Cannot read property 'mainimage' of undefined
My app.js code is below
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './public/images/uploads/');
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now());
}
});
var upload = multer({storage: storage}).single('mainimage');
Then my posts.js
router.post('/add', function(req, res, nect){
// Get The Form Values
var title = req.body.title;
var category = req.body.category;
var body = req.body.body;
var author = req.body.author;
var date = new Date();
if(req.file.mainimage){
var mainImageOriginalName = req.file.mainimage.originalname;
var mainImageName = req.file.mainimage.name;
var mainImageMime = req.file.mainimage.mimetype;
var mainImagePath = req.file.mainimage.path;
var mainImageExt = req.file.mainimage.extension;
var mainImageSize = req.file.mainimage.size;
} else{
var mainImageName = 'noimage.png';
}
//Form Validation
req.checkBody('title', 'Title field is required').notEmpty();
req.checkBody('body', 'Body field is required');
//Check errors
var errors = req.validationErrors();
if(errors){
res.render('addpost',{
"errors": errors,
"title": title,
"body": body
});
} else{
var posts = db.get('posts');
//submit to db
posts.insert({
"title": title,
"body": body,
"category": category,
"date": date,
"author": author,
"mainimage": mainImageName
}, function(err, post){
if(err){
res.send('There was an issue submitting the post');
} else{
req.flash('success', 'Post Submitted');
res.location('/');
res.redirect('/');
}
});
}
});
And this my posts.jade Form
form(method='post', action='/posts/add', enctype='multipart/form-data')
.form-group
label Title:
input.form-control(name='title', type='text')
.form-group
label Category
select.form-control(name='category')
each category, i in categories
option(value='#{category.title}') #{category.title}
.form-group
label Body
textarea.form-control(name='body', id='body')
.form-group
label Main Image:
input.form-control(name='mainimage', type='file', id='mainimage')
And here is where i want to display it
each post, i in posts
.posts
h1
a(href='/posts/show/#{post._id}')
=post.title
p.meta Posted in #{post.category} by #{post.author} on #{moment(post.date).format('MM-DD-YYYY')}
img(src='/images/uploads/#{post.mainimage}')
!=post.body
a.more(href='/posts/show/#{post._id}') Read More
The extension problem is probably because in your storage you name your file without the extension.
To add it, you can insert this code in your storage method.
filename: function (req, file, callback) {
var extension = file.mimetype;
extension = extension.substring(extension.indexOf("/")+1, extension.length);
var filename = file.fieldname + '-' + Date.now() + "." + extension;
callback(null, filename);
}
Also, if you don't have your directory mapped, you can insert in you app.js a static mapping to the folder where you saved the file, like this:
app.use('/images', express.static(path.join(__dirname, 'images')));
Then, in your post page you can access the downloaded file directly via its URL, using http://yourdomain:port/images/<filename.extension>.
Hope it helps.
Related
I added multer to my node js app and it works fine, just the path of the image which I need to store in db isn't correct. Can't find the problem, its obviously some stupid mistake made by me.
This is my setup for multer
const multer = require('multer');
const storage = multer.diskStorage({
destination: './public/images',
filename: function(req, file, next){
next(null, Date.now() + '-' + file.originalname);
}
});
const upload = multer({ storage: storage});
Here is how I use it to store the path
router.post('/add', upload.single('myImage'), function(req, res){
req.checkBody('title','Title is required').notEmpty();
//req.checkBody('author','Author is required').notEmpty();
req.checkBody('body','Body is required').notEmpty();
// Get Errors
let errors = req.validationErrors();
if(errors){
res.render('add_article', {
title:'Add Article',
errors:errors
});
} else {
let article = new Article();
//var date = new Date();
article.title = req.body.title;
article.author = req.user._id;
article.body = req.body.body;
article.descript = req.body.descript;
article.category = req.body.category;
article.date = getDate();
article.time = getTime();
article.comments = 0;
article.img = req.file.path;
console.log(req.file);
article.save(function(err){
if(err){
console.log(err);
return;
} else {
req.flash('success','Article Added');
res.redirect('/');
}
});
}
});
You can see from here that the path isnt right and I can't use it on GET
{ _id: 5bd993756373a5182460aa2a,
title: 'Sport 5',
author: '5acab056708e0d1248cba6ed',
body: 'sadddddddddddddd213',
descript: 'dsadas',
category: 'sport',
date: '2018/10/31',
time: '12:35',
comments: 0,
img: 'public\\images\\1540985717747-nike_logo_slogan_sport_advertising_42643_1280x1024.jpg',
__v: 0 }
Multer is working correctly on your end you just need to convert the system path into a url accessible one.
Here this will help you.
article.comments = 0;
let fileUrl = req.file.path.replace(/\\/g, "/").substring("public".length);
article.img = fileUrl;
This happens in windows because any file path in windows has back slash only but to make the file accessible through url it has to have front slash. So just use the below code to convert all backslash to front slash
const imageUrl = req.file.path.replace("\", "/");
I am trying to upload a file image with multer in express and file is uploading in the directory, but name of the file is not saving in database. I am using mongodb with express. Filename is saving as noimage.png.
routes/posts.js:-
router.post('/add', function(req, res, next) {
if(req.files.mainimage){
console.log('Uploading files...');
// File Info
var mainImageOriginalName = req.files.mainimage.originalname;
var mainImageName = req.files.mainimage.name;
var mainImageMime = req.files.mainimage.mimetype;
var mainImagePath = req.files.mainimage.path;
var mainImageExt = req.files.mainimage.extension;
var mainImageSize = req.files.mainimage.size;
}
else{
var mainImageName = 'noimage.png';
}
//console.log(req.files.mainimage.name);
// Check for errors
var errors = req.validationErrors();
if(errors){
res.render('add', {
errors: errors,
});
}
else{
var posts = db.get('posts');
// Submit to db
posts.insert({
mainimage: mainImageName
}, function(err, post){
if(err){
res.send('There was an issue submitting the post');
}
else{
req.flash('success', 'Post Submitted');
res.location('/posts');
res.redirect('/posts');
}
});
}
});
If you are using multer it seems you didn't specify as multer's specification
router.post('/add', multer({ dest: './uploads/'}).single('myimage'), function(req,res){...})
I am struggling since I am trying to retrieve all the parameters of a POST request in node.js, but it's not gonna work.
Here the post request from the webpage:
var email = $('#email').val();
var name = $('#name').val();
var surname = $('#surname').val();
var role = $('#role').val();
var telephone = $('#telephone').val();
var description = $('#description').val();
$.post('/user/save', {
email : email,
name : name,
surname : surname,
role : role,
telephone : telephone,
description : description
})
.done(function(){
alert('<h2>The new user has been successfully added!</h2>', function(){
clearUserFields();
window.location.reload();
});
})
.fail(function(){
alert('<h2>Sorry, an error occurred during the operation.<br>Please retry later...</h2>', function(){
window.location.reload();
});
});
And this is the route in node.js
// routes file
var postgresql_db_controller = require('../controller/compose-postgresql-connection');
var Q = require ('q');
var bodyParser = require('body-parser');
// route for editing the user
/*
app.get('/user/edit', function(req, res){
retrieveUserInfo().then(function(result){
res.render('admin-profile.ejs', {
title : 'Edit your profile',
admin-info: result
});
});
});
*/
module.exports = function (app) {
// route for routing to "adding a new user" page
app.get('/user/add', function(req, res){
res.render('new-user-profile.ejs', {
title : 'Add a new user'
});
});
//route for routing to "editing the admin user info" page
app.get('/user/admin', function(req, res){
res.render('admin-profile.ejs', {
title : 'Admin profile'
});
});
// route for adding and storing a new user into the postgresql databases
app.post('/user/save', function(req, res){
console.log("routes");
console.log("req.body : " + req.body);
var email = req.params.email;
var name = req.params.name;
var surname = req.params.surname;
var role = req.params.role;
var telephone = req.params.telephone;
var description = req.params.description;
// storing data into database
postgresql_db_controller.postgresql_save_user(email, name, surname, role, telephone, description).then(function(result){
if(result == null){
res.writeHead(404);
res.end();
return;
}
// TO DO
// manage the result (?)
console.log(result);
res.writeHead(200);
res.end();
});
});
// route for creating a new project
// route for searching an existing project
};
and this is the other file:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(bodyParser.json());
var Q = require ('q');
var cfenv = require('cfenv');
// Util is handy to have around, so thats why that's here.
const util = require('util');
// and so is assert
const assert = require('assert');
// Then we'll pull in the database client library
var pg = require('pg');
// get the app environment from Cloud Foundry
var appEnv = cfenv.getAppEnv();
// Within the application environment (appenv) there's a services object
var services = appEnv.services;
// The services object is a map named by service so we extract the one for PostgreSQL
var pg_services = services["compose-for-postgresql"];
// This check ensures there is a services for PostgreSQL databases
// assert(!util.isUndefined(pg_services), "Must be bound to compose-for-postgresql services");
// We now take the first bound PostgreSQL service and extract it's credentials object
var credentials = pg_services[0].credentials;
// Within the credentials, an entry ca_certificate_base64 contains the SSL pinning key
// We convert that from a string into a Buffer entry in an array which we use when
// connecting.
var ca = new Buffer(credentials.ca_certificate_base64, 'base64');
var connectionString = credentials.uri;
// We want to parse connectionString to get username, password, database name, server, port
// So we can use those to connect to the database
var parse = require('pg-connection-string').parse;
config = parse(connectionString);
// Add some ssl
config.ssl = {
rejectUnauthorized: false,
ca: ca
}
// set up a new client using our config details
var client = new pg.Client(config);
// This function to set up the connection with PostgreSQL database
module.exports.postgresql_database_connection = function() {
client.connect(function(err) {
if (err) {
console.log(err);
}
else {
client.query('CREATE TABLE IF NOT EXISTS users (email varchar(256) NOT NULL PRIMARY KEY, name varchar(256) NOT NULL, surname varchar(256) NOT NULL, telephone int NOT NULL, role varchar(256) NOT NULL, description varchar(256) NOT NULL)', function (err,result){
if (err) {
console.log(err);
}
});
}
});
};
// This function is to create and store a new user into the PostgreSQL database with all the needed information
module.exports.postgresql_save_user = function(email, name, surname, role, telephone, description) {
console.log("reading parameters");
var deferred = Q.defer();
// set up a new client using our config details
var client = new pg.Client(config);
client.connect(function(err) {
if (err) {
console.log(err);
deferred.reject();
}
else {
var queryText = 'INSERT INTO users(email,name,surname,telephone,role,description) VALUES(?, ?, ?, ?, ?, ?)';
client.query(queryText, [email, name, surname, telephone, role, description], function (error,result){
if (error) {
console.log(error);
deferred.reject();
}
else {
console.log("Saving the new user into the postegresql database: ");
console.log(result);
//check how result is printed and then manage it where called
deferred.resolve(result);
}
});
}
});
return deferred.promise;
};
It seems there is an error in:
req.params.email
it's not printing anything. I also tried to use req.body.param_name but nothing happen. You know what it is?
Thank you in advance
Try to wrap the data in JSON.Stringify as below.
$.post('/user/save', JSON.Stringify({ email : email, name : name, surname : surname, role : role, telephone : telephone, description : description }))
If you get any error at JSON.Stringify, try to use Json data directly as below.
$.post('/user/save', "{ 'email' : email, 'name' : name, 'surname' : surname, 'role' : role, 'telephone' : telephone, 'description' : description }")
your code does not make use of bodyParser
in app.js (where you start node server), just below var app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
And your route file
// routes file
var postgresql_db_controller = require('../controller/compose-postgresql-connection');
var Q = require ('q');
var bodyParser = require('body-parser');
// route for editing the user
/*
app.get('/user/edit', function(req, res){
retrieveUserInfo().then(function(result){
res.render('admin-profile.ejs', {
title : 'Edit your profile',
admin-info: result
});
});
});
*/
module.exports = function (app) {
// route for routing to "adding a new user" page
app.get('/user/add', function(req, res){
res.render('new-user-profile.ejs', {
title : 'Add a new user'
});
});
//route for routing to "editing the admin user info" page
app.get('/user/admin', function(req, res){
res.render('admin-profile.ejs', {
title : 'Admin profile'
});
});
// route for adding and storing a new user into the postgresql databases
app.post('/user/save', function(req, res){
console.log("routes");
console.log("req.body : " + req.body);
var email = req.body.email;
var name = req.body.name;
var surname = req.body.surname;
var role = req.body.role;
var telephone = req.body.telephone;
var description = req.body.description;
// storing data into database
postgresql_db_controller.postgresql_save_user(email, name, surname, role, telephone, description).then(function(result){
if(result == null){
res.writeHead(404);
res.end();
return;
}
// TO DO
// manage the result (?)
console.log(result);
res.writeHead(200);
res.end();
});
});
// route for creating a new project
// route for searching an existing project
};
Check req.body after console.log("routes"); of your server file and see what parameters you are getting.
like this:-
console.log(req.body)
if you have body parser package then it will show you parameters list which are coming out from client. Once you get the parameters list, you can easily get like req.body.email .
Also change your ajax request like this:-
$.post('/user/save', data: {
"email" : email,
"name" : name,
"surname" : surname,
"role" : role,
"telephone" : telephone,
"description" : description
})
.done(....
Also where is this code..
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
in your server file?
you need to add this in your app file to access bodyparser
I have my post.js as
var express = require('express');
var router = express.Router();
var mongo = require('mongodb');
var db = require('monk')('localhost/nodeblog');
router.get('/add', function(req, res, next) {
var categories = db.get('categories');
categories.find({},{},function (err, categories){
res.render('addpost', {
"title": "Add Post",
'categories': categories
});
});
});
router.post('/add', function(req, res, next){
//get form values
var title = req.body.title;
var category = req.body.category;
var body = req.body.body;
var author = req.body.author;
var date = new Date();
console.log(req.body);
if(req.file){
var mainImageOriginalName = req.file.originalname;
var mainImageName = req.file.filename;
var mainImageSize = req.file.size;
var mainImageMime = req.file.mimetype;
var mainImageExt = req.file.extension;
var mainImagePath = req.file.path;
} else {
var mainImageName = 'noimage.png';
}
//form validation
req.checkBody('title', 'Title field is required').notEmpty();
req.checkBody('body', 'Body field is required').notEmpty();
//check errors
var errors = req.validationErrors();
if(errors){
res.render('addpost', {
'errors' : errors,
'title' : title,
'body' : body
'categories': category
});
} else {
var posts = db.get('posts');
//submit to db
posts.insert({
'title': title,
'body': body,
'category': category,
'date': date,
'author': author,
'image': mainImageName
}, function (err, post){
if(err){
res.send('There was an issue submitting the post');
} else {
req.flash('success', 'Post submitted');
res.location('/');
res.redirect('/');
}
});
}
});
module.exports = router;
and my addpost.jade as
extends layout
block content
h1=title
ul.errors
if errors
each error, i in errors
li.alert.alert-danger #{error.msg}
form(method='post', action='/posts/add', enctype='multipart/form-data')
.form-group
label Title
input.form-control(name='title', type='text')
.form-group
label Category
select.form-control(name='category')
each category, i in categories
option(value='#{category.title}') #{category.title}
.form-group
label Body
textarea.form-control(name='body', id='body')
.form-group
label Main Image
input.form-control(name='image', type='file')
.form-group
label Author
select.form-control(name='author')
option(value='Shehzad Shaikh') Shehzad Shaikh
option(value='John Doe') John Doe
input.btn.btn-default(name='submit', type='submit', value='Save')
script(src='/ckeditor/ckeditor.js')
script
| CKEDITOR.replace('body');
When i submit the form, it gives me an error which says
nodeblog/views/addpost.jade:20 18| label Category 19| select.form-control(name='category') > 20| each category, i in categories 21| option(value='#{category.title}') #{category.title} 22| .form-group 23| label Body Cannot read property 'length' of undefined
I checked the variable names, looks fine to me. What actually went wrong?
Also If something's wrong with the select box, it is rendering the values correctly, however this issue is popping up when submitting the form.
if(errors){
res.render('addpost', {
'errors' : errors,
'title' : title,
'body' : body
});
}
From what I understand, if there is an error during your post, you render the same view providing the errors. Still, you didn't provide categories so it's undefined when Jade(Pug) renders the view. I guess that's where the error comes from... ?
I faced the same problem. Adding an if condition in the jade file solved mine.
.form-group
label Category
select.form-control(name='category')
if categories
each category,i in categories
option(value='#{category.title}') #{category.title}
I have a basic express project created. And I've created a file called lib/userhandler.js inside root folder.
//lib/userhandler.js
exports.addUser = function(req, res){
// Set our internal DB variable
var db = req.db;
// Get our form values. These rely on the "name" attributes
var uName = req.body.username;
var uEmail = req.body.useremail;
// Set our collection
var collection = db.get('usercollection');
// Submit to the DB
collection.insert({
"username" : uName,
"email" : uEmail
}, function (err, doc) {
if (err) {
// If it failed, return error
res.send("There was a problem adding the information to the database.");
}
else {
// If it worked, set the header so the address bar doesn't still say /adduser
//res.location("userlist");
// And forward to success page
res.redirect("userlist");
}
});
}
In my routs/users.js file, whenever the users page is loaded I want to send name and the mail values throught userhandler.js to the database.
//routes/users.js
var express = require('express');
var router = express.Router();
var User = require("../node_modules/SimpleExpress/routes/userhandler.js");
var name = "testuser6";
var mail = "testuser6#testdomain.com";
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
User.addUser(name, mail);
});
module.exports = router;
When I try to load users page it shows "Can't set headers after they are sent."
Thank You
You should try to return the error from your db to your route handler through a callback like this :
//routes/users.js
var express = require('express');
var router = express.Router();
var User = require("../node_modules/SimpleExpress/routes/userhandler.js");
var name = "testuser6";
var mail = "testuser6#testdomain.com";
/* GET users listing. */
router.get('/', function(req, res, next) {
User.addUser(name, mail, function(err, doc) {
if(err) {
res.send("There was a problem adding the information to the database.");
} else {
res.redirect("userlist");
}
});
});
//lib/userhandler.js
exports.addUser = function(name, mail, cb){
// Set our internal DB variable
var db = req.db;
// Set our collection
var collection = db.get('usercollection');
// Submit to the DB
collection.insert({
"username" : name,
"email" : mail
}, function (err, doc) {
cb(err, doc);
});
}
You shouldn't insert the request and response objects as parameters of the function addUser(). They should be in the router callback function. I added a new parameter to the function, so that you can pass the database as a parameter thanks to the router which receives the request object as a parameter.
//lib/userhandler.js
exports.addUser = function(uName, uEmail, db){
var collection = db.get('usercollection');
var result = true;
collection.insert({
"username" : uName,
"email" : uEmail
}, function (err) {
if (err) {
result = false;
}
});
return result; // true or false
}
I changed the code here also, so that the name and email variables can be received from the req and res parameters.
//routes/users.js
var express = require('express');
var router = express.Router();
var User = require("../node_modules/SimpleExpress/routes/userhandler.js");
//var name = "testuser6"; // I don't think you need this
//var mail = "testuser6#testdomain.com"; // and this
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
var db = req.db;
var name = req.body.username;
var mail = req.body.useremail;
if(!User.addUser(name, mail, db)) {
res.send("There was a problem adding the information to the database.");
return;
}
res.redirect('userlist');
});
module.exports = router;
I haven't tested the code because I really don't have time but I hope it works fine.