I write a simple blog. I can save to and edit an article in my blog, but after saving and editing I can't redirect to the admin page. Also, I have an error from my ejs template engine, because of this: I must refresh again to log in to see an admin_page
This is my routes code:
const express = require('express')
const Article = require('../models/article')
const article = require('../models/article')
const router = express.Router()
router.get('/new', (req, res) => {
res.render('admin/article/new', { article: new Article() })
})
router.get('/edit/:id', async(req, res) => {
const article = await Article.findById(req.params.id)
res.render('admin/article/edit', { article: article })
})
router.get('/:slug', async(req, res) => {
const article = await Article.findOne({ slug: req.params.slug })
if (article == null) {
res.redirect('/')
} else {
res.render('admin/article/show', { article: article })
}
})
router.post('/', async(req, res, next) => {
req.article = new Article()
next()
}, saveArticleAndRedirect('new'))
router.put('/:id', async(req, res, next) => {
req.article = await Article.findById(req.params.id)
next()
}, saveArticleAndRedirect('edit'))
router.delete('/:id', async(req, res) => {
await Article.findByIdAndDelete(req.params.id)
res.render('admin/article/index_admin', { articles: articlee() })
})
function articlee() {
return Article.find().sort({ createdAt: 'desc' })
}
function saveArticleAndRedirect(path) {
return async(req, res) => {
const article = req.article
article.title = req.body.title
article.description = req.body.description
article.markdown = req.body.markdown
try {
article = await article.save().then(() => {
res.render('admin/article/index_admin', { articles: articlee() })
// res.redirect('/admin/article/index_admin')
})
} catch (e) {
res.render(`admin/article/${path}`)
}
// function articlee() {
// return Article.find().sort({ createdAt: 'desc' })
}
}
module.exports = router
And this is the admin page code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Blog</title>
</head>
<body>
<div class="container">
<h1 class="mb-4">Blog Article</h1>
New Article
<% articles.forEach ( article => { %>
<div class="card mt-4">
<div class="card-body">
<h4 class="card-title">
<%= article.title %>
</h4>
<div class="card-subtitle text-muted mb-2">
<%= article.createdAt.toLocaleDateString() %>
</div>
<div class="card-text mb-2">
<%=article.description %>
</div>
Read More
Edit
<form action="/admin/article/<%= article.id %>?_method=DELETE" method="POST" class="d-inline">
<button type="submit" class="btn btn-danger ">DELETE</button>
</form>
</div>
</div>
<% }) %>
</div>
</body>
</html>
Related
I'm building a NodeJS Express & MongoDB Web application.
However, since I'm trying to use some AJAX feature to load and display comments on the post page, I'm getting an issue and the "post-detail" page is not displaying.
My code seems fine though. So, I'm not able to find where is the mistake.
When I check this error message:
Failed to load resource: the server responded with a status of 500
(Internal Server Error)
Is there someone who can check my code and let me know what's wrong with it?
I think there is a problem in the route or the paths?
app.js:
const path = require('path');
const express = require('express');
const db = require('./data/database');
const adminRoutes = require('./routes/admin/blog');
const defaultRoutes = require('./routes/home/default');
const postsRoutes = require('./routes/home/posts');
const quotationsRoutes = require('./routes/home/quotations');
const contactsRoutes = require('./routes/home/contacts');
const app = express();
app.set('views', [
path.join(__dirname, 'views/home'),
path.join(__dirname, 'views/admin')
]);
app.set('view engine', 'ejs');
app.use(express.static('public'));
app.use('/public/admin/images', express.static('public/admin/images'));
app.use(express.urlencoded({ extended: true }));
app.use('/', adminRoutes);
app.use('/', defaultRoutes);
app.use('/', postsRoutes);
app.use('/', quotationsRoutes);
app.use('/', contactsRoutes);
app.use(function (req, res) {
res.status(404).render('404');
});
app.use(function (error, req, res, next) {
res.status(500).render('500');
});
db.connectToDatabase().then(function () {
app.listen(3000);
});
routes\home\posts.js:
const express = require('express');
const mongodb = require('mongodb');
// const uuid = require('uuid');
const db = require('../../data/database');
const ObjectId = mongodb.ObjectId;
const router = express.Router();
router.get('/blog', async function (req, res) {
const posts = await db
.getDb()
.collection('posts')
.find({})
.project({ title: 1, summary: 1, 'author.name': 1, imagePath: 1 })
.toArray();
res.render('posts', { posts: posts });
});
router.get('/blog/:id', async function (req, res, next) {
let postId = req.params.id;
try {
postId = new ObjectId(postId);
} catch (error) {
return res.status(404).render('404');
// return next(error);
}
const post = await db
.getDb()
.collection('posts')
.findOne({ _id: postId }, { summary: 0 });
if (!post) {
return res.status(404).render('404');
}
post.humanReadableDate = post.date.toLocaleDateString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
});
post.date = post.date.toISOString();
res.render('post-detail', { post: post });
});
router.get('/blog/:id/comments', async function (req, res) {
const postId = new ObjectId(req.params.id);
const comments = await db
.getDb()
.collection('comments')
.find({ postId: postId })
.toArray();
res.json(comments);
});
router.post('/blog/:id/comments', async function (req, res) {
const postId = new ObjectId(req.params.id);
const newComment = {
postId: postId,
title: req.body.title,
text: req.body.text
};
await db.getDb().collection('comments').insertOne(newComment);
res.redirect('/blog/' + req.params.id);
});
module.exports = router;
views\home\post-detail.ejs:
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('../admin/includes/head', { title: 'Post title' }) %>
<link rel="stylesheet" href="/admin/styles/posts.css" />
<link rel="stylesheet" href="/admin/styles/forms.css" />
<script src="/home/scripts/comments.js" defer></script>
</head>
<body>
<%- include('../admin/includes/header') %>
<main id="post-detail">
<article class="post-item">
<img src="/<%= post.imagePath %>" alt="<%= post.title %>" />
<h1><%= post.title %></h1>
<section id="post-meta">
<address>
<a href="mailto:<%= post.author.email %>"
><%= post.author.name %></a
>
</address>
|
<time datetime="<%= post.date %>"><%= post.humanReadableDate %></time>
</section>
<hr />
<section>
<p id="body"><%= post.body %></p>
</section>
</article>
<section id="comments">
<% if (!comments) { %>
<p>
This post might have comments. You can load them if you want to view
them.
</p>
<button
id="load-comments-btn"
class="btn btn-alt"
data-postid="<%= post._id %>"
>
Load Comments
</button>
<% } else if (comments.length === 0) { %>
<p>No comments found.</p>
<% } else { %>
<ol>
<% for (const comment of comments) { %>
<li><%- include('includes/comment-item', { comment: comment }) %></li>
<% } %>
</ol>
<% } %>
</section>
<section id="comments-form">
<h2>Leave a comment</h2>
<form action="/posts/<%= post._id %>/comments" method="POST">
<div class="form-control">
<label for="title">Comment title</label>
<input type="text" id="title" name="title" required />
</div>
<div class="form-control">
<label for="text">Your comment</label>
<textarea name="text" id="text" rows="3" required></textarea>
</div>
<button class="btn">Save Comment</button>
</form>
</section>
</main>
</body>
</html>
views\home\includes\comments\comment-item.ejs:
<article class="comment-item">
<h2><%= comment.title %></h2>
<p><%= comment.text %></p>
</article>
public\home\scripts\comments.js:
const loadCommentsBtnElement = document.getElementById('load-comments-btn');
async function fetchCommentsForPost() {
const postId = loadCommentsBtnElement.dataset.postid;
const response = await fetch(`/blog/${postId}/comments`);
const responseData = await response.json();
console.log(responseData);
}
loadCommentsBtnElement.addEventListener('click', fetchCommentsForPost);
I have noticed that when I remove the code logic for displaying comments on "post-detail.ejs", the page displays and the form for adding comments as well.
Edit: I added console.error(error) before res.status(500).render('500') and I get the following error message:
ReferenceError:
C:\Users\DELL\Desktop\node-com4muz-filedata-database\views\home\post-detail.ejs:30
28|
29|
30| <% if (!comments) { %>
31|
32| This post might have comments. You can load them if you want to view
33| them.
comments is not defined
at eval ("C:\Users\DELL\Desktop\node-com4muz-filedata-database\views\home\post-detail.ejs":40:8)
at post-detail (C:\Users\DELL\Desktop\node-com4muz-filedata-database\node_modules\ejs\lib\ejs.js:703:17)
at tryHandleCache (C:\Users\DELL\Desktop\node-com4muz-filedata-database\node_modules\ejs\lib\ejs.js:274:36)
at View.exports.renderFile [as engine] (C:\Users\DELL\Desktop\node-com4muz-filedata-database\node_modules\ejs\lib\ejs.js:491:10)
at View.render (C:\Users\DELL\Desktop\node-com4muz-filedata-database\node_modules\express\lib\view.js:135:8)
at tryRender (C:\Users\DELL\Desktop\node-com4muz-filedata-database\node_modules\express\lib\application.js:657:10)
at Function.render (C:\Users\DELL\Desktop\node-com4muz-filedata-database\node_modules\express\lib\application.js:609:3)
at ServerResponse.render (C:\Users\DELL\Desktop\node-com4muz-filedata-database\node_modules\express\lib\response.js:1039:7)
at C:\Users\DELL\Desktop\node-com4muz-filedata-database\routes\home\posts.js:49:7
at processTicksAndRejections (node:internal/process/task_queues:96:5) { path:
'C:\Users\DELL\Desktop\node-com4muz-filedata-database\views\home\post-detail.ejs'
}
I fixed the issue.
On views\home\post-detail.ejs on line 49, I replaced:
res.render('post-detail', { post: post });
by:
res.render('post-detail', { post: post, comments: null });
my index.js file and views/products/edit.ejs files :
const express = require('express')
const path = require('path')
const mongoose = require('mongoose');
const methodOverride = require('method-override')
const app = express()
app.set('view engine', 'ejs')
app.set('views', path.join(__dirname, "views"))
app.use(express.urlencoded({
extended: true
}))
app.use(methodOverride('_method'))
mongoose.connect('mongodb://localhost:27017/farmStand')
.then((data) => {
console.log("successfully connected to database")
console.log(data)
}).catch(error => {
console.log("error occured")
console.log(error)
})
function wrapperASync(fn) {
return function(req, resp, next) {
fn(req, resp, next).catch((e) => {
next(e)
})
}
}
let categories = ['fruits', 'vegetables', 'dairy']
const Product = require('./models/product');
const {
param
} = require('express/lib/request');
app.get('/', (req, resp) => {
resp.send("getting data")
})
app.get('/products', async(req, resp) => {
const {
category
} = req.query
const selectedcategory = category
console.log(selectedcategory)
if (selectedcategory) {
let products = await Product.find({
category: selectedcategory
})
resp.render("products/index", {
products,
selectedcategory
})
} else {
let products = await Product.find({})
// console.log("found products")
resp.render("products/index", {
products,
selectedcategory: "All"
})
}
})
app.get('/products/:id', async(req, resp, next) => {
const {
id
} = req.params
let myproduct = await Product.findById(id)
if (!myproduct) {
return next(new AppError("product not found", 404))
}
// console.log(myproduct)
resp.render('products/details', {
myproduct
})
})
app.get('/product/new', (req, resp) => {
resp.render('products/new', {
categories
})
})
app.get('/products/:id/edit', wrapperASync(async(req, resp, next) => {
const {
id
} = req.params
const product = await Product.findById(id)
if (!product) {
throw new AppError("product not found", 404)
}
resp.render('products/edit', {
product,
categories
})
}))
app.put('/products/:id', wrapperASync(async(req, resp, next) => {
const {
id
} = req.params
const updatedValues = req.body
const newvalue = await Product.findByIdAndUpdate(id, updatedValues, {
runValidators: true,
new: true
})
// console.log(newvalue)
resp.redirect(`/products/${newvalue._id}`)
}))
app.post('/products', wrapperASync(async(req, resp) => {
const newdoc = req.body
const myproduct = new Product(newdoc)
console.log(myproduct)
await myproduct.save()
resp.redirect(`/products/${myproduct._id}`)
}))
app.delete('/products/:id', async(req, resp, next) => {
try {
const {
id
} = req.params
const deleted_product = await Product.findOneAndDelete(id)
resp.redirect('/products')
} catch (error) {
next(error)
}
})
app.use((err, req, resp, next) => {
console.log(err.name)
next(err)
})
app.use((err, req, resp, next) => {
const {
status = 404, message = "something went wrong"
} = err
resp.status(status).send(message)
})
app.listen(3000, () => {
console.log("server started successfully")
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1> enter product details</h1>
<form action="/products/<%= product.id %>?_method=PUT " method="POST">
<label for="name">enter the name of the product : </label>
<input type="text" name="name" id="name" placeholder="name" value="<%= product.name %> ">
<label for="price">enter the price in dollars : </label>
<input type="number" name="price" id="price" placeholder="price" value="<%= product.price %>">
<label for="category">category : </label>
<select name="category" id="category">
<% for(category of categories) { %>
<option value="<%= category %>" <%=p roduct.category===c ategory ? "selected": '' %> >
<%= category %>
</option>
<% } %>
</select>
<button>add new details</button>
</form>
<section>
exit
</section>
</body>
</html>
my models/product.js file :
const mongoose = require('mongoose')
const productSchema = new mongoose.Schema({
name : {
type : String,
required : true
},
price:{
type : Number,
required : true,
min : 0
},
category:{
type:String,
lowercase :true,
enum : ["fruits","vegetables","dairy"]
}
})
const Product = new mongoose.model('Product',productSchema);
module.exports = Product;
my problem : I have installed all the dependencies my problem is when I am entering in to the edit page and then when I type my id incorrect and of different length in the url for which Iam listening for I get the CastError printed out on my console and when I keep my name Field as blank and edit then I get the ValidationError printed out on my console but after getting the validation error when I change the id of the product which is incorrect again and which is of different length in the url after getting validation error response and send the request in chrome my server gets error and breaks even though I handle the error of my /products/:id put route
please help me
The project is on my github:
https://github.com/vabmoni/luiztools
I followed this tutorial:
https://www.luiztools.com.br/post/tutorial-crud-em-node-js-com-driver-nativo-do-mongodb/
but when I edit the customer, I have an error 404.
To run the project:
Install MongoDB Server
Add MongoDB /bin folder to PATH
Open first CMD: mongod --dbpath C:{Your Path}\webapp\data
Open second CMD: mongo
Open third CMD: npm install and npm start
routes/index.js
var express = require('express');
var router = express.Router();
router.get('/', async (req, res, next) => {
try {
const docs = await global.db.findAll();
res.render('index', { title: 'Lista de Clientes', docs });
} catch (err) {
next(err);
}
});
router.get('/new', (req, res, next) => {
res.render('new', { title: 'Novo Cadastro', doc: { "nome": "", "idade": "" }, action: '/new' });
})
router.post('/new', async (req, res, next) => {
const nome = req.body.nome;
const idade = parseInt(req.body.idade);
try {
const result = await global.db.insert({ nome, idade });
console.log(result);
res.redirect('/');
} catch (err) {
next(err);
}
});
router.post('/edit/:id', async (req, res) => {
const id = req.params.id;
const nome = req.body.nome;
const idade = parseInt(req.body.idade);
try {
const result = await global.db.update(id, { nome, idade });
console.log(result);
res.redirect('/');
} catch (err) {
next(err);
}
});
router.get('/delete/:id', async (req, res) => {
const id = req.params.id;
try {
const result = await global.db.deleteOne(id);
console.log(result);
res.redirect('/');
} catch (err) {
next(err);
}
});
module.exports = router;
views/index.ejs
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1><%= title %></h1>
<ul>
<% docs.forEach(function(customer){ %>
<li>
<a href="/edit/<%= customer._id %>">
<%= customer.nome %>
</a>
<a href="/delete/<%= customer._id %>"
onclick="return confirm('Tem certeza que deseja excluir?');">
X
</a>
</li>
<% }) %>
</ul>
<hr />
Cadastrar novo cliente
</body>
</html>
views\new.ejs
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1><%= title %></h1>
<form action="<%= action %>" method="POST">
<p>Nome:<input type="text" name="nome" value="<%= doc.nome %>" /></p>
<p>Idade:<input type="number" name="idade" value="<%= doc.idade %>" /></p>
<input type="submit" value="Salvar" />
</form>
</body>
</html>
db.js
const mongoClient = require("mongodb").MongoClient;
mongoClient.connect("mongodb://localhost")
.then(conn => global.conn = conn.db("webapp"))
.catch(err => console.log(err))
function findAll() {
return global.conn.collection("customers").find().toArray();
}
function insert(customer) {
return global.conn.collection("customers").insertOne(customer);
}
const ObjectId = require("mongodb").ObjectId;
function findOne(id) {
return global.conn.collection("customers").findOne(new ObjectId(id));
}
function update(id, customer) {
return global.conn.collection("customers").updateOne({ _id: new ObjectId(id) }, { $set: customer });
}
function deleteOne(id) {
return global.conn.collection("customers").deleteOne({ _id: new ObjectId(id) });
}
module.exports = { findAll, insert, findOne, update, deleteOne }
i get the this error
121| <div class="container-fluid bg-dark text-white" style="margin-top: 2%;">
122|
>> 123| <h1 class="mb-1 text-center"><%= article.title %> </h1>
124| </div>
125| <div class="container-fluid blog-footer">
126| <p>Simqle Team | Bütün Hakları Saklıdır | Hakkımızda <b> | </b>Nedim Talha.</p>
article is not defined
on this code
const express = require('express');
const router = express.Router();
const Article = require('../models/article');
router.get('/new', (req, res) => {
res.render('articles/new', { article: new Article() })
})
router.get('/:id', async(req, res) => {
const article = await Article.findById(req.params.id)
if(article == null) res.redirect('/')
res.render('articles/show')
})
router.post('/', async(req, res) => {
var article = new Article({
title: req.body.title,
description: req.body.description,
markdown: req.body.markdown
})
try {
article = await article.save()
res.redirect(`/articles/${article.id}`)
} catch(err) {
res.render('articles/new', { article: article })
}
})
module.exports = router
I could not solve this error
You're not passing the article in render
it should be like this
res.render('articles/show', { article })
i've got a problem which i can't resolve for some time now, i tried to research but nothing comes to my mind.
First of all - This is my app:
server.js
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const MongoClient = require('mongodb').MongoClient
app.use(bodyParser.urlencoded({ extended: true }))
app.use("/node_modules", express.static('node_modules'));
app.use(express.static(__dirname + '/static'));
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html')
})
app.post('/quotes', (req, res) => {
db.collection('quotes').save(req.body, (err, result) => {
if (err) return console.log(err)
console.log(req.body)
console.log('saved to database')
res.redirect('/')
})
})
var db
MongoClient.connect('mongodb://127.0.0.1/db', (err, database) => {
if (err) return console.log(err)
db = database
app.listen(3000, () => {
console.log('listening on 3000')
})
})
index.html
<!DOCTYPE html>
<html ng-app='app'>
<head>
<link rel="stylesheet" href="/assets/css/my.css" />
</head>
<body>
<div ng-controller='PostsCtrl' class='container'>
<h1>
<center>Shoutbox</center>
</h1>
Your Nick
<form role='form'>
<div class='form-group'>
<div class="input-group">
<input ng-model="postName" class='form-control'>
</div>
</div>
</form>
Your Shout
<form role='form'>
<div class='form-group'>
<div class="input-group">
<input ng-model="postBody" class='form-control'>
<span class='input-group-btn'>
<button ng-click='addPost()' class='btn btn-default'>Add Shout</button>
</span>
</div>
</div>
</form>
<ul class='list-group'>
<li ng-repeat='post in posts' class='list-group-item'>
<strong>#{{ post.username }}</strong>
<span>{{ post.body }}</span>
</li>
</ul>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script>
var app = angular.module('app', [])
app.controller('PostsCtrl', function($scope, $http) {
$scope.addPost = function() {
$http({
method: 'POST',
url: '/quotes',
data: {
"Object": "Value"
}
}).then(function(success) {
console.log("sent")
}, function(error) {
cosnole.log(err)
});
if ($scope.postBody) {
$scope.posts.unshift({
username: $scope.postName,
body: $scope.postBody
}),
$scope.postBody = ''
$scope.postName = ''
}
}
$scope.posts = []
})
</script>
</body>
</html
Now here's my problem:
Everything seems to be ok, data is sent but when i'm browsing mongo for entries - only ID is saved, no data whatsoever.
I have no idea where it's going wrong.
This is what's saved to database:
{ _id: 59304d915d20041a272bd96d }
When i manually save json to database - it works ok so i assume thats not problem with mongo itself.
Thanks for every hint you provide.
/edit
Apparently i have resolved the issue by using app.use( bodyParser.json() ); on the server side.
To be closed.