Jade cannot read property length - javascript

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}

Related

Problem rendering dust template in nodejs

I keep getting this error below after posting a form using expressjs and a dust template. The form is meant to redirect after posting.
The main error lies around the router.post section it seems the problem only occurs after I try to redirect using res.redirect.
VError: Problem rendering dust template "C:\Users\USER\Desktop\nodejs\Node-Bookstore\public\templates\manage\books\add.dust": The "path" argument must be of type string. Received an instance of Chunk
at Stub.callback (C:\Users\USER\Desktop\nodejs\Node-Bookstore\node_modules\adaro\lib\engine.js:167:30)
at Stub.flush (C:\Users\USER\Desktop\nodejs\Node-Bookstore\node_modules\dustjs-linkedin\lib\dust.js:564:14)
at Chunk.setError (C:\Users\USER\Desktop\nodejs\Node-Bookstore\node_modules\dustjs-linkedin\lib\dust.js:1051:15)
at C:\Users\USER\Desktop\nodejs\Node-Bookstore\node_modules\dust-usecontent-helper\index.js:25:27
at C:\Users\USER\Desktop\nodejs\Node-Bookstore\node_modules\dust-makara-helpers\index.js:50:21
at C:\Users\USER\Desktop\nodejs\Node-Bookstore\node_modules\iferr\index.js:13:50
at FSReqCallback.readFileAfterClose [as oncomplete] (internal/fs/read_file_context.js:63:3)
It only happens after res.redirect()
My code:
'use strict';
var Book = require('../models/bookmodel');
var Category = require('../models/categorymodel');
module.exports = function (router) {
router.get('/', function (req, res){
res.render('manage/index');
});
// Get Books
router.get('/books', function (req, res){
Book.find({},{}, function (err, books){
if (err){
console.log(err);
}
var model = {
books: books
}
res.render('manage/books/index', model);
});
});
// Get add book
router.get('/books/add', function (req, res){
Category.find({},{}, function (err, categories){
if (err){
console.log(err);
}
var model = {
categories: categories
}
console.log("before rendered manage/books/add");
res.render('manage/books/add', model);
});
});
//Post the details from the add books page!
router.post('/books', function (req, res){
var title = req.body.title && req.body.title.trim();
var category = req.body.category && req.body.category.trim();
var author = req.body.author && req.body.author.trim();
var publisher = req.body.publisher && req.body.publisher.trim();
var price = req.body.price && req.body.price.trim();
var description = req.body.description && req.body.description.trim();
var cover = req.body.cover && req.body.cover.trim();
if (title == '' || price == "") {
req.flash('error', 'Please input the price and title');
res.location('/manage/books/add');
res.redirect('/manage/books/add');
console.log("Empty title or price");
}
else if (isNaN(price)) {
req.flash('error', 'Price must be a number!');
res.location('/manage/books/add');
res.redirect('/manage/books/add');
console.log("price is NaN");
}else {
var newBook = new Book({
title: title,
category: category,
description: description,
author: author,
publisher: publisher,
cover: cover,
price: price,
});
newBook.save(function(err){
if (err){
console.log('save failed: ', err);
}
req.flash('success', 'New Book Added!');
res.location('/manage/books');
res.redirect('/manage/books');
console.log("was able to redirect");
});
}
});
router.get('/categories', function (req, res){
res.render('manage/categories/index');
});
};
Note: There is nothing wrong with the add.dust file
For some reason req.flash() was the issue here. Apparently I can't use the same syntax used in Jade with Dust
This will be added to the main index.js file in your root folder where you initialised the middel-ware for connect-flash
app.use(flash());
app.use(function (req, res, next) {
var messages = require('express-messages')(req, res);
res.locals.messages = function (chunk, context, bodies, params) {
return chunk.write(messages());
};
next();
});
Note that the messages function asks for (chunk, context, bodies, params) parameters and returns return chunk.write(messages());
Next:
Represent the message function with {#messages /} in your dust template

Getting parameters of post request in node js

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 can't upload images using multer and express

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.

node js - not uploading imagename and says profileimage is undefined

the project contains 3 files which are listed below
the thing is happening when i try to change the if from (req.file.profileImage) to (req.file) it works but it always send the default name and not uploading the requested file and if i leave it (req.file.profileImage) if gives an error when i try to submit the form >>
Cannot read property 'profileimage' of undefined
1- users.js
var express = require('express');
var router = express.Router();
var User=require('../models/user.js');
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
router.get('/register', function(req, res, next) {
res.render('register', {
'title': 'Register'
});
});
router.get('/login', function(req, res, next) {
res.render('login', {
'title': 'Login'
});
});
router.post('/register', function(req, res, next) {
var name = req.body.name;
var email = req.body.email;
var username = req.body.username;
var password = req.body.password;
var password2 = req.body.password2;
// Check for Image Field
if(req.file.profileimage) {
console.log('uploading File...');
console.log("i am the if" );
// File Info
var profileImageOriginalName = req.file.profileimage.originalname;
var profileImageName = req.file.profileimage.name;
var profileImageMime = req.file.profileimage.mimetype;
var profileImagePath = req.file.profileimage.path;
var profileImageExt = req.file.profileimage.extension;
var profileImageSize = req.file.profileimage.size;
} else {
// Set a Default Image
var profileImageName = 'noimage.png';
console.log("im the else");
}
console.log(req.file);
console.log(profileImageName);
// Form Validation
req.checkBody('name','Name field is required').notEmpty();
req.checkBody('email','Email field is required').notEmpty();
req.checkBody('email','Email not valid').isEmail();
req.checkBody('username','Username field is required').notEmpty();
req.checkBody('password','Password field is required').notEmpty();
req.checkBody('password2','Password do not match').equals(req.body.password);
// Check for errors
var errors = req.validationErrors();
if(errors){
res.render('register', {
errors: errors,
name: name,
email: email,
username: username,
password: password,
password2: password2
});
} else {
var newUser = new User({
name: name,
email: email,
username: username,
password: password,
profileImage: profileImageName
});
}
// Create User
User.createUser(newUser, function(err, user){
if(err)throw err;
console.log(user);
});
//Success Message
req.flash('success', 'You are noew registered and may log in');
res.location('/');
res.redirect('/');
});
module.exports = router;
# 2-models/user.js#
var mongoose = require('mongoose');
//var bcrypt = require('bcrypt');
mongoose.connect('mongodb://localhost/nodeauth');
var db = mongoose.connection;
// User Schema
var UserSchema = mongoose.Schema({
username: {
type: String,
index: true
},
password: {
type: String,
required: true,
bcrypt: true
},
email: {
type: String
},
name: {
type: String
},
profileImage: {
type: String
}
});
var User = module.exports = mongoose.model('User', UserSchema);
module.exports.createUser = function(newUser,callback){
// Create User
newUser.save(callback);
}
# 3-register.jade which containing the form#
extends layout
block content
h1 Register
p Please register using the form below
ul.errors
if errors
each error, i in errors
li.alert.alert-danger #{error.msg}
form(method='post', action='/users/register',endtype='multipart/form-data')
.form-group
label Name
input.form-control(name='name', type='text', placeholder='Enter Name')
.form-group
label Email
input.form-control(name='email', type='email', placeholder='Enter Email')
.form-group
label Username
input.form-control(name='username', type='text', placeholder='Usernamee')
.form-group
label Password
input.form-control(name='password', type='password', placeholder='Enter Password')
.form-group
label Password
input.form-control(name='password2', type='password', placeholder='Confirm Password')
.form-group
label Profile Image
input.form-control(name='profileImage', type='file')
input.btn.btn-default(name='submit', type='submit', values='Register')**

Adding a date()/timestamp to each MongoDB item upon creation

this is my second question today regarding Node.js. It's late, and I'd like some help to quickly integrate this function before I can go to bed.
I have a small Q&A app in which I can read and write data from/to MongoDB on my views pages.
However, I'd like to make a timestamp or date() register itself with each instance of items being written to MongoDB.
On the views, for now, only the author, title and body of text must be visible. But when I query Mongo, I'd like to have a seperate property that lists the date and time created. (Date alone suffices)
I have defined a property "date" : Date, in my Schema. I assumed it would automatically add this, but only title, author and body are added. I think it is because they are defined as vals in the routes for discussions but I'm note sure.
These are my code files:
discussions.js -- /routes
var mongoose = require('mongoose');
var express = require('express');
var router = express.Router();
var Discussion = require('../models/discussions');
router.get('/', function(req, res, next){
// alle db records uitlussen, op render alldiscussions
var db = req.db;
Discussion.find({},{},function(e,docs){
res.render('all_discussions', {
"all_discussions" : docs
});
console.log(docs);
});
});
router.get('/create', function(req, res, next){
res.render('add_discussion', {title: 'Diskussr'});
});
router.post('/submit', function(req, res) {
//set DB
var db = req.db;
//form vals
var author = req.body.name;
var title = req.body.title;
var body = req.body.body;
//set collection
var collection = db.get('discussions');
//insert
collection.insert({
"author" : author,
"title" : title,
"body" : body
}, function (err, doc) {
if (err) {
res.send("Database submit error");
}
else {
res.location("all_discussions");
res.redirect("all_discussions");
}
});
});
module.exports = router;
add_discussion.jade -- /views
extends layout
block content
h1 Start a discussion
p Start a discussion here on #{title} and help eachother out.
p Voeg hier uw vraag in:
form(action="/submit" method="post" name="submit_discussion")
input(id="name", placeholder="Your name" name="name")
br
br
input(id="title", placeholder="Brief summary of your problem." name="title")
br
br
input(id="body", placeholder="Explain your problem." name="body")
br
br
button(type="sumbit" id="submit" value="submit") Submit
br
discussions.js -- /models
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//schema discussions
var DiscussionSchema = new Schema({
author: String,
title: String,
body: String,
category: String,
created: Date
},
{ collection : 'discussions' });
// model
var Discussion = mongoose.model('Discussion', DiscussionSchema, 'discussions');
// test functie: aanmaken vraag on load
// var firstDiscussion = new Discussion({author: "Testuser 1", title: "Testvraag via models"});
// console.log(firstDiscussion);
// //vraag saven
// firstDiscussion.save(function (err, firstDiscussion){
// if (err) return console.error(err);
// });
module.exports = Discussion;
Just add a default value for the created field:
//schema discussions
var DiscussionSchema = new Schema({
author: String,
title: String,
body: String,
category: String,
created: { type: Date, default: Date.now }
},
{ collection : 'discussions' });
Or, since you are using ObjectId as primary key, you can extract the timestamp using getTimestamp() as suggested by #adeneo:
Discussion.find({}, function(e,docs){
docs.forEach(function(doc) {
console.log("created: " + doc._id.getTimestamp());
});
});

Categories