I am new in nodejs, mongoose, express and I am trying to create a basic twitter clone. When I want to create a new tweet and hit the submit button nothing happens.
Here is my code:
app.js
var express = require("express"),
mongoose = require("mongoose"),
bodyParser = require("body-parser"),
ejs = require("ejs");
var app = express();
mongoose.connect("mongodb://localhost:27017/twitter_clone", {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log("CONNECTED TO DB"))
.catch((error) => console.log(error.message));
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static(__dirname + '/public'));
app.set("view engine", "ejs");
// MONGODB TWEETS SCHEMA
var tweetsSchema = new mongoose.Schema({
text: String
})
var Tweets = mongoose.model("Tweets", tweetsSchema);
//================
//RESTFUL ROUTES
//================
// INDEX ROUTES
app.get("/", function(req, res){
Tweets.find({}, function(err, allTweets){
if(err){
console.log(err);
} else {
res.render("home", {newtweet:allTweets});
}
})
})
app.get("/explore", function(req, res){
res.render("explore");
})
app.get("/notifications", function(req, res){
res.render("notifications");
})
app.get("/messages", function(req, res){
res.render("messages");
})
app.get("/bookmarks", function(req, res){
res.render("bookmarks");
})
app.get("/lists", function(req, res){
res.render("lists");
})
app.get("/profile", function(req, res){
res.render("profile");
})
app.get("/more", function(req, res){
res.render("more");
})
// NEW ROUTES
app.get("/tweet/new", function(req, res){
res.render("new");
})
// POST
app.post("/posttweet", function(req, res){
var text = req.body;
var newtweet = {textmessage: text};
Tweets.create(newtweet, function(err, newTweet){
if(err){
console.log(err)
} else {
res.redirect("/");
}
})
})
app.listen(5000, function(){
console.log("Server listening on port 5000");
})
home.ejs:
<div class="middlewelcome">
<h3>Welcome to twitter!</h3>
<p id="welcomingp">This is the best place to see what’s happening in your world. Find some people and topics <br> to follow now.</p>
<button id="getstarted" class="bluebutton">Get Started</button>
</div>
<div class="tweets">
<% newtweet.forEach(function(newtweet){ %>
<div class="showtweets">
<h1>
<%= newtweet.text %>
</h1>
</div>
<% }) %>
</div>
</div>
I tried to manually save a new text previously and it's working fine, so I don't know what would be a problem and why my post route not working
IntweetsSchema the text field is named text but in your POST route you call it textmessage. Try renaming the value in the POST route to match the schema.
app.post("/posttweet", function(req, res){
var text = req.body;
var newtweet = {text: text}; // typo error
Tweets.create(newtweet, function(err, newTweet){
if(err){
console.log(err)
} else {
res.redirect("/");
}
})
})
schema you defined and object you are passing are not matching
Related
I am using the following dependencies:
express session
passport
passport-local
passport-local-mongoose
When I try to register a user and they post the data. The data get saved to the database but it give a bad request. Also when I try to use req.user.id in the Tweet.find() it gives undefined and I also console.log(req.user) and it give me undefined. And once a error came that failed to serialize session one or two time. Can anybody help me. Here is some code sorry in advance if this is to much code as I was not sure that which part of the code was important.
//-----------------------//Require---------------------
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const ejs = require("ejs");
const session = require("express-session");
const passport = require("passport");
const LocalStratagy= require("passport-local").Strategy;
const passportLocalMongoose = require("passport-local-mongoose");
const mongoose = require("mongoose");
//-----------------------//App.use---------------------
app.use(express.static("public"));
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({extended: true}));
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: false
}));
//-----------------------//Passport---------------------
app.use(passport.initialize());
app.use(passport.session());
//-----------------------//Mongoose---------------------
mongoose.connect('mongodb://localhost/Twitter', {useNewUrlParser: true, useUnifiedTopology: true});
mongoose.set('useCreateIndex', true);
const tweetschema = new mongoose.Schema({
username: String,
password: String,
tweets: String
});
//-----------------------//Schema Plgin---------------------
tweetschema.plugin(passportLocalMongoose);
//-----------------------//New Model---------------------
const Tweet = new mongoose.model("Tweet", tweetschema);
//-----------------------//Local Strategy-------------------
passport.use(new LocalStratagy(Tweet.authenticate()));
//-----------------------//Seralize Passport---------------------
passport.serializeUser(function(user, done) {
console.log(user);
done(null, user.id);
});
//-----------------------//Desarlize Passport---------------------
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
app.post("/tweets", bodyParser.urlencoded({extended: true}), (req, res)=>{
const Gottweets= req.body.tweet;
console.log(Gottweets);
console.log(req.user);
/* Tweet.findById(req.tweet.id, (err, foundUser)=>{
if(err){
console.log(err);
res.redirect("/tweets");
}else{
if(foundUser){
foundUser.tweets = Gottweets;
foundUser.save(()=>{
res.redirect("/");
})
}
}
})
*/
});
app.post("/regsiter",bodyParser.urlencoded({extended: true}), (req, res)=>{
console.log(req.body.email);
Tweet.register({username: req.body.email}, req.body.password, (err, user)=>{
if(err){
console.log(err);
res.redirect("/regsiter");
}else{
if(user){
passport.authenticate("local")(req, res, function(){
res.redirect("/regsiter");
})
}
}
})
});
<%- include('partials/header') %>
<form action="/regsiter" method="post" class="login">
<label for="emial" class="email">
Email
<input type="email" name="email" id="email">
</label>
<label for="password">
Password
<input type="password" name="password" id="password">
</label>
<div class="soicalLogin">
Facebook
Google
</div>
<button type="submit">Register</button>
</form>
<%- include('partials/footer') %>
You can try rewriting your POST /register endpoint with this example
app.post("/register",bodyParser.urlencoded({extended: true}), (req, res, next) => {
console.log(req.body.email);
Tweet.register({username: req.body.email}, req.body.password, (err, user)=>{
if(err){
console.log(err);
res.redirect("/regsiter");
return;
}
if(!user){ // also handle the case where user is undefined
return res.status(500).json({ yourMessage: 'error' });
}
next();
})
}, passport.authenticate("local", { successRedirect: '/', failureRedirect: '/register' }));
It's not a good idea to override the next function given to passport.authenticate("local")
Now the error should be gone, let me know if this code sample doesn't work.
Hope it helps
I am currently making a basic twitter clone. Everything went perfect before my text started not showing up when I made a post request.
What would be the problem?
My code:
app.js:
var express = require("express"),
mongoose = require("mongoose"),
bodyParser = require("body-parser"),
ejs = require("ejs");
var app = express();
mongoose.connect("mongodb://localhost:27017/twitter_clone", {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log("CONNECTED TO DB"))
.catch((error) => console.log(error.message));
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static(__dirname + '/public'));
app.set("view engine", "ejs");
// MONGODB TWEETS SCHEMA
var tweetsSchema = new mongoose.Schema({
text: String
})
var Tweets = mongoose.model("Tweets", tweetsSchema);
//================
//RESTFUL ROUTES
//================
// INDEX ROUTES
app.get("/", function(req, res){
Tweets.find({}, function(err, allTweets){
if(err){
console.log(err);
} else {
res.render("home", {newtweet:allTweets});
}
})
})
app.get("/explore", function(req, res){
res.render("explore");
})
app.get("/notifications", function(req, res){
res.render("notifications");
})
app.get("/messages", function(req, res){
res.render("messages");
})
app.get("/bookmarks", function(req, res){
res.render("bookmarks");
})
app.get("/lists", function(req, res){
res.render("lists");
})
app.get("/profile", function(req, res){
res.render("profile");
})
app.get("/more", function(req, res){
res.render("more");
})
// NEW ROUTES
app.get("/tweet/new", function(req, res){
res.render("new");
})
// POST
app.post("/posttweet", function(req, res){
var text = req.body.text;
var newtweet = {text: text};
Tweets.create(newtweet, function(err, newTweet){
if(err){
console.log(err)
} else {
res.redirect("/");
}
})
})
//DELETE
app.get("/delete/:id", function(req,res){
mongoose.model("Tweets").remove({_id:req.params.id}, function(err, delData){
res.redirect("/");
})
})
app.listen(5000, function(){
console.log("Server listening on port 5000");
})
home.ejs:
<form action="/tweet/new">
<input class="bluebutton" type="submit" value="Tweet" />
</form>
<div class="tweets">
<% newtweet.forEach(function(newtweet){ %>
<div class="showtweets">
<p class="tweetcontent">
<%= newtweet.text %>
</p>
</div>
<% }) %>
</div>
I asked a similar question before and I found a solution and it worked well for a while, but I made some changes and now it's not working poroperly.
Create a form that sends a post request to "/posttweet":
<form action="/posttweet" method="post">
<input type="text" name="text" />
<input type="submit" value="Tweet" />
</form>
This should make the right request to your single post route.
Edit
Tip: Make sure to send back some response from your handlers, even if its an error, otherwise your server will just hang.
I am trying to store MongoDB data in a variable and use it for display in HTML using hbs. The error I am getting is TypeError: Cannot read property 'collection' of undefined. Here is the code I wrote:
evar express = require('express');
var bodyParser = require('body-parser');
var mongoDB = require('mongodb').MongoClient;
var hbs = require('hbs');
var app = express();
app.use(express.static(__dirname +'/public'));
app.use( bodyParser.urlencoded());
var url = 'mongodb://localhost:27017';
var db;
mongoDB.connect(url, {useUnifiedTopology: true, useNewUrlParser: true }, function(error, client){
if(error)
throw error;
db = client.db('attainu');
});
app.post('/addstudent/add', function(req, res){
db.collection('students').insertOne(req.body, function(error, result){
if(error)
throw error;
res.json(result);
console.log("New student Successfully Added!");
})
})
var students = db.collection('students').find({}).toArray();
app.get('/allstudents', function(req, res){
res.render('students.hbs', {
student: students
});
})
app.listen(3000);
in the HTML file:
<body>
{{#each student}}
<div class="card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">this.name</h5>
<p class="card-text">this.email + this.age</p>
this.number
</div>
</div>
{{/each}}
</body>
I think this is because JS is asynchronous language. It would be helpful if anyone could help me make this an asynchronous code.
try
app.get('/allstudents', function(req, res){
db.collection('students').find({},(err,students)=>{
res.render('students.hbs', {
student: students
});
});
})
app.get("/allstudents", async (req, res)=>{
await db.collection("students").find({}, (error, students)=> {
if(error) console.log(error);
res.render("students.hbs", {
student: students
})
})
})
Use async to wait for your database operation to finish before continuing
Using Javascript, NodeJS, MongoDB, Express
In my app a user is suppose to type in the input field and when they click the submit button the text gets appended to the page. I am able to successfully post text to the page but when I refresh my browser, my post do not show up. I think I need to do a get request through ajax in the script section of my partials/test.ejs, but I am unsure how to execute this.
models/Blog.js
var
mongoose = require('mongoose'),
Schema = mongoose.Schema,
BlogSchema = new Schema({
name: String
})
var Blog = mongoose.model('Blog', BlogSchema)
module.exports = Blog
views/partials/test.ejs
<body>
<form>
<button type="submit" class="btn btn-default pull-right" id="create">Submit</button>
</form>
<div class="feedback-messages"></div>
</body>
<script type="text/javascript">
var messages = $('.feedback-messages')
var postItem = $("#create")
postItem.on('click', function(evt) {
evt.preventDefault();
$.ajax({
url: '/test',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({data: newItem})
})
.done(function(data) {
console.log("Hello");
messages.append(newItem)
})
routes/index.js
var
express = require('express');
router = express.Router();
bodyParser = require('body-parser');
mongoose = require('mongoose');
Blog = require('../models/Blog.js');
// route for home page
router.get('/', function(req, res) {
res.render('./partials/home');
});
//route for test page
router.get('/test', function(req, res) {
res.render('./partials/test');
});
router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: false}));
router.get('/test', function(req, res){
Blog.find({}, function(err, blog){
if(err) return console.log(err)
res.json(blog);
})
});
router.post('/test', function(req, res){
// console.log(req.body)
Blog.create({content: req.body.data}, function(err, item){
if(err) return console.log(err)
res.json({serverSays: "Request received. Added item.", item: item})
})
})
module.exports = router;
try changing you code for saving into this
Blog.create({content: req.body.data})
.then(function(item){
res.json({serverSays: "Request received. Added item.", item: item})
})
.catch(function(err) {
return console.log(err)
})
I am using Node.js Passport and I'm trying to figure out how to display username after a successful login. After reading the documentation I've verified that i have Sessions and Middleware configured which is what I need but what are my next steps?
This is my users.js file:
var express = require('express');
var router = express.Router();
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');
// Home
router.get('/index', function(req, res){
res.render('index');
});
// Profile
router.get('/profile', function(req, res){
res.render('profile');
});
// Register
router.get('/register', function(req, res){
res.render('register');
});
// Login
router.get('/login', function(req, res){
res.render('login');
});
// About-us
router.get('/about-us', function(req, res){
res.render('about-us');
});
// Register User
router.post('/register', function(req, res){
var email = req.body.email;
var username = req.body.username;
var password = req.body.password;
// Validation
req.checkBody('username', 'Username is Required').notEmpty();
req.checkBody('email', 'Email is required').notEmpty();
req.checkBody('email', 'Email is not valid').isEmail();
req.checkBody('password', 'Password is required').notEmpty();
var errors = req.validationErrors();
if(errors){
res.render('register',{
errors:errors
});
} else {
var newUser = new User({
email:email,
username: username,
password: password,
});
User.createUser(newUser, function(err, user){
if(err) throw err;
console.log(user);
});
req.flash('success_msg', 'You are now registered. Log In!');
res.redirect('/users/login');
}
});
passport.use(new LocalStrategy(
function(username, password, done) {
User.getUserByUsername(username, function(err, user){
if(err) throw err;
if(!user){
return done(null, false, {message: 'User does not exist!'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.getUserById(id, function(err, user) {
done(err, user);
});
});
router.post('/login',
passport.authenticate('local', {successRedirect:'/users/profile', failureRedirect:'/users/login',failureFlash: true}),
function(req, res) {
res.redirect('/users/profile')
});
router.get('/logout', function(req, res){
req.logout();
req.flash('success_msg', '');
res.redirect('/');
});
module.exports = router;
And this is my app.js file:
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var exphbs = require('express-handlebars');
var expressValidator = require('express-validator');
var flash = require('connect-flash');
var session = require('express-session');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongo = require('mongodb');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/loginandregister');
var db = mongoose.connection;
var routes = require('./routes/index');
var users = require('./routes/users');
// Init App
var app = express();
// View Engine
app.set('views', path.join(__dirname, 'views'));
app.engine('handlebars', exphbs({defaultLayout:'layout'}));
app.set('view engine', 'handlebars');
// BodyParser Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
// Set Static Folder
app.use(express.static(path.join(__dirname, 'public')));
app.use('/public', express.static('public'));
// Express Session
app.use(session({
secret: 'secret',
saveUninitialized: true,
resave: true
}));
// Passport init
app.use(passport.initialize());
app.use(passport.session());
// Express Validator
app.use(expressValidator({
errorFormatter: function(param, msg, value) {
var namespace = param.split('.')
, root = namespace.shift()
, formParam = root;
while(namespace.length) {
formParam += '[' + namespace.shift() + ']';
}
return {
param : formParam,
msg : msg,
value : value
};
}
}));
// Connect Flash
app.use(flash());
// Global Vars
app.use(function (req, res, next) {
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
res.locals.error = req.flash('error');
res.locals.user = req.user || null;
next();
});
app.use('/', routes);
app.use('/users', users);
// Set Port
app.set('port', (process.env.PORT || 3000));
app.listen(app.get('port'), function(){
console.log('Server started on port '+app.get('port'));
});
I've read a similar question on the site and the answer stated that:
app.get('/example', function(req, res) {
res.render('index', { username: req.user.username });
});
needs to be implemented. But I am confused as to where and how? I tried placing it into to my users.js file but i get a "ReferenceError: app is not defined" error in terminal when restarting the node app.
What are my next steps? Any and every help is valued and appreciated. Thank you.
EDIT:
I added
router.get('/profile', function(req, res){
res.render('profile', { username: req.user.username });
});
to my users.js file and added:
<header>
<h1>Hello?</h1>
{{#if user}}
<p>Hello {{username}}</p>
{{else}}
<p>Please <a href='/users/login'>Log In</a></p>
{{/if}}
</header>
to my profile.handlebars page but still no username display. What am i missing???
SOLUTION: Apparently my code was correct and my problem was solved hours ago however it was hiding in plain site. I am using Firefox to build my site and Chrome to conduct all my research and web searching. After DEEP searching i stumbled upon another similar question to my own and this guy complained that he had <p>Hi, {{username}}</p> within his index file but only Hi was showing up within his browser. On the contrary neither Hi or {{username}} was showing in my browser. My entire <p> tag was missing. So i simply loaded my site in Chrome and there it was problem solved! Bad practice on my part for only using one browser but that's what I get for silly mistakes :)
You need to use the rendering part of the mentioned part of this code:
app.get('/example', function(req, res) {
res.render('index', { username: req.user.username });
});
i.e., res.render('index', { username: req.user.username }); at the right/required path.
like you can try using it as
router.get('/profile', function(req, res){
res.render('profile', { username: req.user.username });
});
and consume(use) the rendered variable username in your view for displaying.
If this doesn't work or you have some other problem, refer Nodejs Passport display username also.
My workaround was adding the req.user (if it exists, thus when loggedin) to the rendering. I've included both a hello, {{user}} and Dynamic navbar example.
I don't know if it's because I use handlebars instead of express-handelbars but the example I used to make this does not have to send the req.user object along for the render. It automatically sends it along? So I feel like my workaround is unnecesary if I do it right?
Edit: this solution only works for 1 page. If you go to another route it doesn't send the object along anymore.
Edit2: Apparently with express 4 sending the user object along in req.user is the only way I've found so far. But you'll have to send it along every route that requests data from the data base as well.
Confirmed edit 2 through this example: https://github.com/passport/express-4.x-local-example/blob/master/server.js
// Get Homepage
router.get('/', function(req,res){
Job.find({})
.exec(function(err, jobs){
if(err){
res.send('Error occured', err);
} else {
res.render('jobs', {jobs, user:req.user});
}
});
});
<nav>
<ul class="nav nav-pills pull-right">
{{#if user}}
<li role="presentation"><span class="glyphicons glyphicons-user"></span><p style='color:white'>Hello {{user.name}}</p></li>
<li role="presentation">Logout</li>
{{else}}
<li role="presentation">Login</li>
<li role="presentation">Register</li>
{{/if}}
</ul>
</nav>