Cannot read property 'id' of undefined. Express - mysql

The full code is following - pretty simply i wanna add, delete or update posts - when i do one of the things by them self it works but togther it breaks
Iv'd searched alot in the NodeJS MySQL which i use to query the database
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
port : 3306,
database: 'nodeproject',
user : 'noderoot',
password : 'default'
});
var express = require('express');
var http = require('http');
var path = require('path');
var exphbs = require('express3-handlebars');
var qs = require('querystring');
var app = express();
app.set('port', process.env.PORT || 8000);
app.set('views', path.join(__dirname, 'views'));
app.engine('handlebars', exphbs({defaultLayout: 'main'}));
app.set('view engine', 'handlebars');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
configQuery = function() {
connection.config.queryFormat = function (query, values) {
if (!values) return query;
return query.replace(/\:(\w+)/g, function (txt, key) {
if (values.hasOwnProperty(key)) {
return this.escape(values[key]);
}
return txt;
}.bind(this));
};
}
index = function(req, res){
/*connection.connect(function(err){
if(err != null) {
res.end('Error connecting to mysql:' + err+'\n');
}
});*/
connection.query("SELECT * FROM posts", function(err, rows){
if(err != null) {
res.end("Query error:" + err);
} else {
var myOuterRows = [];
for (var i = 0; i < rows.length; i++) {
var myRows = rows[i];
myOuterRows.push(myRows);
};
res.render('index', {
title: 'Express Handlebars Test',
posts: myOuterRows
});
}
});
};
addpost = function(req, res) {
var post = {
id: req.body.post.id,
postTitle: req.body.post.postTitle,
postContent: req.body.post.postContent,
published: req.body.post.published
};
connection.query('INSERT INTO posts SET ?', post, function(err, result) {
console.log("Neat! you entered a post");
});
res.redirect("/");
}
editpost = function(req, res) {
configQuery();
var edit = {
id: req.body.editpost.id,
postTitle: req.body.editpost.postTitle,
postContent: req.body.editpost.postContent
};
var queryTitle = connection.query("UPDATE posts SET ?", edit, function(err, result) {
console.log("Neat! you editted a post")
});
res.redirect("/");
}
deletepost = function(req, res) {
configQuery();
var deleteThis = {
id: req.body.deletepost.id
};
console.log(deleteThis);
var queryDelete = connection.query("DELETE FROM posts WHERE id = :id", {
id: deleteThis.id
});
res.redirect("/");
}
app.get('/', index);
app.post('/', addpost);
app.post('/', editpost);
app.post('/', deletepost);
//app.get('/list', list);
http.createServer(app).listen(8000, function(){
console.log('Express server listening on port ' + app.get('port'));
});
The error i get is following:
500 TypeError: Cannot read property 'id' of undefined
at editpost (C:\dev\ExpressHbsMysql\app.js:96:24)
at callbacks (C:\dev\ExpressHbsMysql\node_modules\express\lib\router\index.js:164:37)
at param (C:\dev\ExpressHbsMysql\node_modules\express\lib\router\index.js:138:11)
at pass (C:\dev\ExpressHbsMysql\node_modules\express\lib\router\index.js:145:5)
at Router._dispatch (C:\dev\ExpressHbsMysql\node_modules\express\lib\router\index.js:173:5)
at Object.router (C:\dev\ExpressHbsMysql\node_modules\express\lib\router\index.js:33:10)
at next (C:\dev\ExpressHbsMysql\node_modules\express\node_modules\connect\lib\proto.js:193:15)
at Object.methodOverride [as handle] (C:\dev\ExpressHbsMysql\node_modules\express\node_modules\connect\lib\middleware\methodOverride.js:48:5)
at next (C:\dev\ExpressHbsMysql\node_modules\express\node_modules\connect\lib\proto.js:193:15)
at C:\dev\ExpressHbsMysql\node_modules\express\node_modules\connect\lib\middleware\urlencoded.js:83:7

Where should it go?
app.post('/', addpost);
app.post('/', editpost);
app.post('/', deletepost);
To addpost or to editpost or to deletepost
As far as i can tell from your code i suggest you keep different urls for each handler that way you will tell which handler to call, right now all your post requests call first handler which is addpost
Map your handlers like this
app.post('/post/add', addpost);
app.post('/post/edit', editpost);
app.post('/post/delete', deletepost);
Next in your forms or if your are using ajax post your addrequest to '/post/add', editrequest to /post/edit and so on.

Related

Where to place code to show data from MySQL to Handlebars?

Goal:
I am aiming to teach myself how to use Node JS, MySQL and express.
I'm struggling to understand where to place my code for loading MySQL data into HTML.
Let me show you the whole code.
app.js
var express = require('express');
var mysql = require('mysql');
var dotenv = require('dotenv');
var path = require('path');
var cookieParser = require('cookie-parser');
dotenv.config({path: './.env'});
var app = express();
// Connection to MySQL
var db = mysql.createConnection({
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE
});
db.connect(function(error) {
if(error) {
console.log(error);
}
else{
console.log("Connected");
}
});
// Parse URL-Encoded bodies
app.use(express.urlencoded({extended: false}));
// Parse JSON bodies
app.use(express.json());
// Initialize a cookie
app.use(cookieParser());
// View engine to control HTML
app.set('view engine', 'hbs');
// Public dir
var publicDir = path.join(__dirname, './public');
app.use(express.static(publicDir));
// Define routes
app.use('/', require('./routes/pages'));
app.use('/auth', require('./routes/auth'));
app.listen(3000, function() {
console.log("Server is running on port 3000");
});
routes/pages.js
var express = require('express');
var authController = require('../controllers/auth');
var router = express.Router();
// Home
router.get("/", authController.isLoggedIn, function(req,res) {
res.render("index", {
user: req.user
});
});
// Register
router.get("/register", function(req, res) {
res.render("register");
});
// Login
router.get("/login", function(req, res) {
res.render("login");
});
// Profile
router.get('/profile', authController.isLoggedIn, function(req, res) {
if(req.user) {
res.render('profile', {
user: req.user
});
}
else {
res.redirect('login');
}
});
// Forum
router.get('/forums', authController.isLoggedIn, function(req, res) {
if(req.user) {
res.render('forums');
} else {
res.redirect('login');
}
});
// English Division //
// Premier League
router.get('/Leagues/EnglishDivision', authController.isLoggedIn, function(req, res) {
if(req.user) {
res.render('PremierLeague');
} else {
res.redirect('../../login');
}
});
module.exports = router;
routes/auth.js
var express = require('express');
var authController = require('../controllers/auth');
var router = express.Router();
// Register
router.post("/register", authController.register);
// Login
router.post("/login", authController.login);
// Logout
router.get('/logout', authController.logout);
module.exports = router;
controllers/auth.js
var mysql = require('mysql');
var jwt = require('jsonwebtoken');
var bcrypt = require('bcryptjs');
var {promisify} = require('util');
// Connection to MySQL
var db = mysql.createConnection({
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE
});
// Register function
exports.register = function(req, res) {
console.log(req.body);
var {name, email, password, passwordConfirm} = req.body;
db.query("SELECT email FROM users WHERE email = ?", [email], function(error, result) {
if(error){
console.log(error);
}
if(result.length > 0) {
return res.render('register', {
message: 'That email is already in use'
})
} else if(password !== passwordConfirm) {
return res.render('register', {
message: 'Passwords do not match'
});
}
let hashedPassword = bcrypt.hashSync(password, 8);
console.log(hashedPassword);
// Insert user details into MySQL
db.query('INSERT INTO users set ?', {name: name, email: email, password: hashedPassword, dateJoined: new Date()}, function(error, result) {
if(error) {
console.log(error);
} else {
console.log(result);
return res.render('register', {
message: 'User registered'
});
}
});
});
}
// Login function
exports.login = function(req, res) {
try {
var {email, password} = req.body;
if(!email || !password) {
return res.status(400).render('login', {
message: 'Please provide an email and password'
});
}
db.query('SELECT * FROM users WHERE email = ?', [email], async function(error, result) {
console.log(result);
if(!result.length > 0 || !(await bcrypt.compare(password, result[0].password))) {
res.status(401).render('login', {
message: 'The email or password is incorrect'
});
}
else {
var id = result[0].id;
// Create a token
var token = jwt.sign({id}, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN
});
console.log("The token is " + token);
// Create a cookie
var cookieOptions = {
expires: new Date(
Date.now() + process.env.JWT_COOKIE_EXPIRES * 24 * 60 * 60 * 1000
),
httpOnly: true
}
// Set up a cookie
res.cookie('jwt', token, cookieOptions);
res.status(200).redirect("/");
}
});
} catch (error) {
console.log(error);
}
}
// Check if logged in
exports.isLoggedIn = async function(req, res, next) {
console.log(req.cookies);
if(req.cookies.jwt){
try {
// Verify the token
var decoded = await promisify(jwt.verify)(req.cookies.jwt, process.env.JWT_SECRET);
console.log(decoded);
// Check if user exist
db.query("SELECT id, name, email, password, date_format(datejoined, '%d/%m/%Y') as dateJoined FROM users WHERE id = ?", [decoded.id], function(error, result) {
console.log(result);
// If no result
if(!result) {
return next();
}
req.user = result[0];
return next();
});
}
catch (e) {
console.log(e);
return next();
}
} else{
next();
}
}
// Logout function
exports.logout = async function(req, res) {
res.clearCookie('jwt');
res.status(200).redirect('/');
}
Question
In my .hbs file called PremierLeague I'd like to load MySQL data in HTML format. Where in the code below I need to start?
Desired goal:
This is when the user clicks into view premier league
Foreach record in MySQL I'd like to add a new card for each record. I know how to use HandleBars {{some.data}}.
I just don't get where I code the query?
Does it needs to be in a controller or can it be in in the router.get(...?
Also how do I use {{#foreach}} correctly ?
You don't need any other specific controller, the right place to code the query is actually the route itself.
But before entering the core of your question, let's talk a while about your code.
I can see you are performing connection to database more than once, you could add database dedicated controller, something like:
controllers/db.js
var mysql = require('mysql');
var dotenv = require('dotenv');
dotenv.config({path: './.env'});
// Connection to MySQL
var db = mysql.createConnection({
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE
});
function connect(done) {
db.connect(done);
}
module.exports = { db: db, connect: connect };
this let you access to the database instance from every file with just one line:
var db = require('./controllers/db').db;
than you could use the connect function in your app:
app.js
var express = require('express');
var db = require(./controllers/db);
var path = require('path');
var cookieParser = require('cookie-parser');
// set up your server
var app = express();
// Parse URL-Encoded bodies
app.use(express.urlencoded({extended: false}));
// Parse JSON bodies
app.use(express.json());
// Initialize a cookie
app.use(cookieParser());
// View engine to control HTML
app.set('view engine', 'hbs');
// Public dir
var publicDir = path.join(__dirname, './public');
app.use(express.static(publicDir));
// Define routes
app.use('/', require('./routes/pages'));
app.use('/auth', require('./routes/auth'));
// finally run your server only if you can connect to the database
db.connect(function(error) {
if(error) return console.log("Error connecting to the database:", error);
app.listen(3000, function() {
console.log("Server is running on port 3000");
});
});
you could also simplify you controllers/auth.js removing database connection stuff and using only the line to require your database controller.
Finally you can code your query:
routes/pages.js
var express = require('express');
var authController = require('../controllers/auth');
var db = require('../controllers/db').db;
var router = express.Router();
// Omissis... other routes
// Premier League
router.get('/Leagues/EnglishDivision', authController.isLoggedIn, function(req, res) {
// a good practice is first to handle possible exit cases to reduce nesting levels
if(! req.user) return res.redirect('../../login');
// this is actually the right place to perform queries
db.query('SELECT ...', [...], function(error, results) {
// once again first possible exit cases
if(error) return res.status(500).end(error.message)
res.render('PremierLeague', { results: results });
});
});
module.exports = router;
Last in your PremierLeague.hbs file you can handle the results in a #foreach directive.
Just pass your data when you render the view
router.get('/Leagues/EnglishDivision', authController.isLoggedIn, function(req, res) {
if(req.user) {
connection.query('SELECT * FROM EnglishDivision',function (err,results) {
if (err) throw err;
res.render('PremierLeague',{data: results});
});
} else {
res.redirect('../../login');
}
});
then in the .hbs file
{{#each data}}
<div class="card">
<h3>{{this.someData}}</h3>
<h2>{{this.someData}}</h2>
</div>
{{/each}}

When I upload image through multer , I got image undefined error

I am using it with node and mysql with angular 5.
const express = require('express');
const mysql = require('mysql');
const bodyParser = require('body-parser');
const path = require('path');
const cors = require('cors');
const router = express.Router();
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './assets/images/')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
});
const fileFilter = (req, file, cb)=>{
if(file.mimetype === 'image/jpeg' || file.mimetype === 'image/png'){
cb(null, true);
}
else{
cb(null, false);
}
};
upload = multer({
storage: storage,
limits:{
filesize : 1024 * 1024 * 5
},
fileFilter : fileFilter
});
const app = express();
//DATABASE CONNECTION
const connection = mysql.createConnection({
host: 'localhost',
user:'root',
password: 'root',
database: 'inpblog',
port: 8889
});
// ALLOW CROSS ORIGIN
const corsOptions = {
origin: 'http://localhost:4200',
origin1: 'http://localhost:4202',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
};
app.use(cors(corsOptions));
app.use('./assets/images', express.static(path.join(__dirname, 'dist', 'upload')));
const jsonParser = bodyParser.json();
const urlencodedParser = bodyParser.urlencoded({ extended: false });
connection.connect(function(error){
if(!!error){
console.log("error - db not connected");
}
else{
console.log("connected");
}
});
Here i define the code to upload a image in mysql database. through postman its upload a image in destination folder with multer middleware but when i upload a image through ng form its showing error in console."image undefined" and submit the "c:/fakepath/image.jgg" in mysql.
Here is the API to insert the post
app.post('/insertPost', upload.single('txt_blog_image'), jsonParser, (req, res) => {
console.log("image: ", req.file); // working fine only with postman
//console.log("rBody: ", req.body.txt_blog_image); // working fine only with Angular
let blogFields = {
post_author : req.body.txt_blog_author,
post_image : req.body.txt_blog_image
};
let sql = 'INSERT INTO insdb SET ?';
let query = connection.query(sql, blogFields, (err,result)=> {
res.send('New Post added...');
});
});
// Get All Post
app.get('/getallposts', (req, res) => {
let sql = 'SELECT * FROM insdb';
let query = connection.query(sql, (err, results) => {
if(err) throw err;
console.log(results);
res.send(results);
});
});
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
app.listen(4202);
Try this way.
var path = require('path');
var multer = require('multer');
var storage = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, './assets/images/')
},
filename: function(req, file, callback) {
console.log(file)
callback(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
}
})
In your api :
app.post('/getallposts',upload.single("image") , function(req, res) {
let sql = 'SELECT * FROM insdb';
let query = connection.query(sql, (err, results) => {
if(err) throw err;
console.log(results);
res.send(results);
});
})
From Angular side :
let form = new FormData();
form.append('image' , file);
Then console in server side , req.files to check file is coming or not ?
For more information and example please see this link

How can i resolve 'Cannot set headers after they are sent to the client'

How can I resolve Cannot set headers after they are sent to the client:
app.js
var express = require('express');
var session = require('express-session');
var mongoose = require('mongoose');
var app = express();
var ejs = require('ejs');
var port = 3000;
var bodyParser = require('body-parser');
var mongoDB = "mongodb://localhost:27017/vinavdb";
app.set('views', __dirname + '/admin') app.engine('html', ejs.renderFile);
app.set('view engine', 'ejs');
app.set('trust proxy', 1);
app.use(session({
secret: 'dsghbrtdfhbdfg64545TRYFFHGGJNN',
resave: false,
saveUninitialized: true
}))
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
var sess;
mongoose.Promise = global.Promise;
mongoose.connect(mongoDB, {
useNewUrlParser: true
});
var nameSchema = new mongoose.Schema({
firstname: String,
lastname: String,
email: String,
password: String
});
var User = mongoose.model("User", nameSchema);
app.get("/", (req, res) => {
sess = req.session;
if (sess.email) {
res.redirect("/admin");
} else {
res.sendFile(__dirname + "/index.html");
}
});
app.get("/login", (req, res) => {
res.sendFile(__dirname + "/login.html");
});
app.post("/addname", function(req, res) {
var myData = new User(req.body);
User.findOne({
email: req.body.email
}, function(err, resv) {
if (resv == null) {
myData.save().then(item => {
res.send("Name saved to database")
}).catch(err => {
res.status(400).send("Unable to save to database");
});
res.send("ThankYou For your Registration")
} else if (resv.email == req.body.email) {
res.send("Email is already registered");
} else {
res.send("Srry data is not allowed");
}
});
});
app.post("/login", function(req, res, next) {
User.findOne({
email: req.body.email
}, function(err, vals) {
if (vals == null) {
res.end("Invalid Logins");
} else if (vals.email == req.body.email && vals.password == req.body.password) {
sess = req.session;
sess.email = req.body.email;
res.redirect('/admin');
} else {
res.send("Srry data is not allowed");
}
});
});
app.route('/admin').get(function(req, res, next) {
sess = req.session;
if (sess.email) {
res.send(__dirname + "/admin/index.html");
} else {
res.write('Please login first.');
}
})
app.listen(port, () => {
console.log("Server listening on port " + port);
});
Cause of your error : You are trying to send a response of a single request twice.
One request have one response.
Once response is send, you cannot send it again for the same request.In your /addname API, You are trying to send response twice. So remove one.
Here .save() is asynchronous function so node will not wait and execute
res.send("ThankYou For your Registration") first and later once record will be saved it will try to send res.send("Name saved to database") so you are getting error here.
app.post("/addname", function(req, res) {
var myData = new User(req.body);
User.findOne({
email: req.body.email
}, function(err, resv) {
if (resv == null) {
myData.save().then(item => {
console.log("Name saved to database")
res.send("ThankYou For your Registration")
}).catch(err => {
res.status(400).send("Unable to save to database");
});
} else if (resv.email == req.body.email) {
res.send("Email is already registered");
} else {
res.send("Srry data is not allowed");
}
});
});
After you execute a res.send you cannot call it again in the same request, it only allows one response per request. In your code, I think in this part it can happens:
if (resv == null) {
myData.save().then(item => {
res.send("Name saved to database")
}).catch(err => {
res.status(400).send("Unable to save to database");
});
res.send("ThankYou For your Registration")
}
In this if, when you are saving myData you are sending a response, but asynchronously you already sent another response previously ("ThankYou For your Registration").
Hope it helps

Creating a new model doesn't work - no error

i am using node-orm2 with mysql in my project. I have already created the database tables, and i can query/find data in my DB. However, when i want to insert new data, nothing happens - no error in the callback, nothing.
Here is the relevant code:
Model class:
module.exports = function (orm, db) {
var Comment = db.define('comment', {
body: {type: 'text'}
});
};
Index.js in the model folder:
var orm = require('orm');
var settings = require('../config/settings');
var connection = null;
function setup(db, cb) {
require('./comment')(orm, db);
return cb(null, db);
}
module.exports = function (cb) {
if (connection) return cb(null, connection);
orm.connect(settings.database, function (err, db) {
if (err) return cb(err);
connection = db;
db.settings.set('instance.returnAllErrors', true);
db.settings.set('connection.debug', true);
setup(db, cb);
});
};
Controller:
var orm = require('orm');
exports.create = function(req, res){
var testcomment = {};
testcomment.body = "test comment";
req.models.comment.create(testcomment, function (err, message) {
if (err) return console.log(err);
return res.send(200, message);
});
};
Environment.js
var path = require('path');
var express = require('express');
var settings = require('./settings');
var models = require('../models/');
var logger = require('morgan');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
module.exports = function (app) {
app.use(express.static(path.join(settings.path, 'public')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(methodOverride());
app.use(function (req, res, next) {
models(function (err, db) {
if (err) return next(err);
req.models = db.models;
req.db = db;
return next();
});
})
};
Settings.js:
var path = require('path');
var settings = {
path : path.normalize(path.join(__dirname, '..')),
port : process.env.NODE_PORT || 3001,
database : {
protocol : "mysql",
host : "localhost",
port : "3306",
database : "taxidatabase",
user : "root",
password : "admin"
}
};
module.exports = settings;
I basically followed the pattern in the example application in node-orm2 - but it doesn't work. Any idea, why?
Thanks!
Before adding anything to table you need to sync the DB at least once after you define the models in order to create the tables:
var models = require('../app/models/');
models(function (err, db) {
if (err) throw err;
db.sync(function (err) {
if (err) throw err;
console.log('Done!');
});
});
Or maybe syncing the comment model will do:
var orm = require('orm');
exports.create = function(req, res){
var testcomment = {};
testcomment.body = "test comment";
req.models.comment.create(testcomment, function (err, message) {
if (err) return console.log(err);
return res.send(200, message);
});
req.models.comment.sync(function (err) {
if (err) throw err;
console.log('Done!');
});
};

How to return a JSON object using NodeJS, Passport, mongoose, & MongoDB

I'm new to NodeJS, Passport, and Mongo. I'm trying to set up a basic local authentication, which is successful, however, when I try to return the entire object it returns an empty array.
My node setup:
var express = require('express');
var routes = require('./routes');
var user = require('./routes/user');
var http = require('http');
var path = require('path');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose/');
mongoose.connect('mongodb://localhost:27017/EiData');
var Schema = mongoose.Schema;
var UserDetail = new Schema({
username: String,
password: String,
fullname: String
}, {
collection: 'userlist'
});
var UserDetails = mongoose.model('userlist', UserDetail);
var User_obj = user;
var app = express();
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use( express.cookieParser() );
app.use(express.session({ secret: 'plsrespond' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
So, my tactic is to set a global variable named User_Obj, and set it to be the user object that passport returns. However, I feel like it might be a scope problem, since my global variable is empty when I call it.
Here's my Passport Authentication logic:
passport.use(new LocalStrategy(function(username, password, done) {
process.nextTick(function() {
UserDetails.findOne({
'username': username,
}, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false);
}
if (user.password != password) {
return done(null, false);
}
return done(null, user);
});
});
}));
Lastly, my success/failure redirects, and where I attempt to call my User_obj global variable:
app.post('/login',
passport.authenticate('local', {
successRedirect: '/loginSuccess',
failureRedirect: '/loginFailure'
})
);
app.get('/loginFailure', function(req, res, next) {
res.send('Invalid code!');
});
app.get('/loginSuccess', function(req, res, next) {
res.json(User_obj)
});