Getting a "Cannot read property of undefined" error - javascript

I'm trying to retrieve a random value (id) in a dynamic way to as to be able to find a specific product in the future (I'm following a nodejs course from udemy and the instructor is building an online commerce webpage as an example). I've reviewed the code the instructor has written on the video over and over to make sure the error's not on the syntaxis end, it clearly isn't since all's written exactly as it shows in the videos yet I keep on getting the error, if anyone can help please! I've got no clue what it could be since at this point I understand the error could be on the logic end of it, I don't know if maybe I'm not understanding the logic well and therefore the mistake i'm making isn't obvious to me yet.
I'll give the community some of the code so you guys can give me a hdn, thank you all !
Error thrown in console:
TypeError: Cannot read property 'productId' of undefined
at exports.getProduct (C:\Users\TOMAS\Desktop\node js MVC\controllers\shop.js:14:29)
at Layer.handle [as handle_request] (C:\Users\TOMAS\Desktop\node js MVC\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\TOMAS\Desktop\node js MVC\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\Users\TOMAS\Desktop\node js MVC\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\Users\TOMAS\Desktop\node js MVC\node_modules\express\lib\router\layer.js:95:5)
at C:\Users\TOMAS\Desktop\node js MVC\node_modules\express\lib\router\index.js:281:22
at param (C:\Users\TOMAS\Desktop\node js MVC\node_modules\express\lib\router\index.js:354:14)
at param (C:\Users\TOMAS\Desktop\node js MVC\node_modules\express\lib\router\index.js:365:14)
at Function.process_params (C:\Users\TOMAS\Desktop\node js MVC\node_modules\express\lib\router\index.js:410:3)
at next (C:\Users\TOMAS\Desktop\node js MVC\node_modules\express\lib\router\index.js:275:10)
product.js file:
const fs = require('fs');
const path = require('path');
const p = path.join(
path.dirname(process.mainModule.filename),
'data',
'products.json'
);
const getProductsFromFile = cb =>{
fs.readFile(p, (err, fileContent) => {
if(err) {
cb([]);
} else{
cb(JSON.parse(fileContent));
}
});
}
module.exports = class Product {
constructor(title, imageUrl, description, price) {
this.title = title;
this.imageUrl = imageUrl;
this.description = description;
this.price = price;
}
save() {
this.id = Math.random().toString();
getProductsFromFile(products => {
products.push(this);
fs.writeFile(p, JSON.stringify(products), (err) => {
console.log(err);
});
});
}
static fetchAll(cb) {
getProductsFromFile(cb);
};
};
shop.js file:
const Product = require('../models/product');
exports.getProducts = (req, res, next) => {
Product.fetchAll(products => {
res.render('shop/product-list', {
prods: products,
pageTitle: 'All Products',
path: '/products'
});
});
};
exports.getProduct = (res, req, next) => {
const prodId = req.params.productId;
console.log(prodId);
res.redirect('/');
};
exports.getIndex = (req, res, next) => {
Product.fetchAll(products => {
res.render('shop/index', {
prods: products,
pageTitle: 'Shop',
path: '/'
});
});
};
exports.getCart = (req, res, next) => {
res.render('shop/cart', {
path: '/cart',
pageTitle: 'Your Cart'
});
};
exports.getOrders = (req, res, next) => {
res.render('shop/orders', {
path: '/orders',
pageTitle: 'Your Orders'
});
};
exports.getCheckout = (req, res, next) => {
res.render('shop/checkout', {
path: '/checkout',
pageTitle: 'Checkout'
});
};
product-list.ejs file:
<%- include('../includes/head.ejs') %>
<link rel="stylesheet" href="/css/products.css">
</head>
<body>
<%- include('../includes/navigation.ejs') %>
<main>
<% if (prods.length > 0) {%>
<div class="grid">
<div class="card">
<% for (let product of prods) { %>
<article class="product-item">
<header class="card__header">
<h1 class="product__title"> <%= product.title %> </h1>
</header>
<div class="card__image">
<img src="<%= product.imageUrl %>", alt="">
</div>
<div class="card__content">
<h2 class="product__price"> $<%= product.price %> </h2>
<p class="product__description"> <%= product.description %> </p>
</div>
<div class="card__actions">
Details
<form action="/add-to-cart" method="POST">
<button class="btn"> Add to Cart </button>
</form>
</div>
</article>
<% } %>
</div>
</div>
<% } else { %>
<h1>No Products</h1>
<% } %>
</main>
<%- include('../includes/end.ejs') %>
users.js file:
const path = require('path');
const express = require('express');
const shopController = require('../controllers/shop');
const router = express.Router();
router.get('/', shopController.getIndex);
router.get('/products', shopController.getProducts);
router.get('/products/:productId', shopController.getProduct);
router.get('/cart', shopController.getCart);
router.get('/orders', shopController.getOrders);
router.get('/checkout', shopController.getCheckout);
module.exports = router;

In shop.js, you need to swap your req and res, your request comes first, then response, then next.
exports.getProduct = (req, res, next) => {
const prodId = req.params.productId;
console.log(prodId);
res.redirect('/');
};

base of
at exports.getProduct (C:\Users\TOMAS\Desktop\node js MVC\controllers\shop.js:14:29)
you have error on shop.js line 14. means :
const prodId = req.params.productId;
req or params is undefined and
TypeError: Cannot read property 'productId' of undefined

Related

Failed to load resource: the server responded with a status of 500 (Internal Server Error) - NodeJs Express & MongoDB Web Application

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 });

node.js Form data doesn't render and creates an empty object in mogoDb

Hey guys I'am trying to make a blog website in node.js with mongoDB. But the form data doesn't show on home page as it should. It shows some errors while running like:
in home.js it says
1. "Cannot read properties of undefined (reading 'substring')"
2. "blogDB> db.posts.find()
[
{ _id: ObjectId("62f5341c3fb15b1283671737"), __v: 0 },
{ _id: ObjectId("62f537843fb15b128367173a"), __v: 0 }
]"
empty objects gets created when submit button is clicked in the form
//app.js
const postSchema = new mongoose.Schema({
title: {
type: String
},
content: {
type: String
}
});
const Post = mongoose.model("Post", postSchema);
app.get("/", function (req, res) {
Post.find({}, function (err, foundposts) {
if (foundposts.length > 0) {
res.render("home", {
startingContent: homeStartingContent,
posts: foundposts
});
} else {
res.render('home', {
startingContent: homeStartingContent,
posts: []
});
}
});
});
app.get("/compose", function (req, res) {
res.render('compose');
});
app.post("/compose", function (req, res) {
const post = new Post({
title: req.body.newPostNewPage_Title,
content: req.body.newPostNewPage_Content
});
post.save(function (err) {
if (!err)
res.redirect("/");
});
});
app.get("/posts/:postId", function (req, res) {
const requestedPostId = req.params.postId;
posts.forEach(function (post) {
Post.findOne({_id: requestedPostId}, function(err, post){
res.render("post",{
title: post.title,
content: post.content
});
});
})
});
//home.js
<%- include("partials/header") -%>
<h1 style="color: rgb(118, 202, 70);">Home</h1>
<p>
<%=startingContent%>
</p>
<% posts.forEach(function(post){ %>
<h1>
<%=posts.title %>
</h1>
<p>
<%=post.content.substring(0, 100) + " ..." %>
Read More
</p>
<% }); %>
<%- include("partials/footer") -%>

How do I get my express app to refresh data from mongodb server without having to refresh the page?

I'm having trouble with getting blog posts to show up on the home page of my express blog app...they get saved (confirmed using mongo shell), but what happens after I click to save a composed post is the app will redirect to an empty home page (except for the default top material). That is, the short version of the post I just composed doesn't appear until I refresh the page manually.
My code:
mongoose.connect('mongodb://localhost:27017/blogDB', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const postSchema = new mongoose.Schema({
title: {
type: String,
required: [true, 'missing blog post title']
},
content: {
type: String,
required: [true, 'missing blog post content']
}
});
const Post = mongoose.model('Post', postSchema);
app.get('/', (req, res) => {
Post.find({}, (err, returnedItems) => {
if (!err) res.render('home', { homeStartingContent, returnedItems });
});
});
app.post('/compose', (req, res) => {
const post = new Post({
title: req.body.postTitle,
content: req.body.postBody
});
post.save();
res.redirect('/');
});
/* ----------------------------------------------------------- */
<%- include('partials/header'); %>
<h1>Home</h1>
<p><%= homeStartingContent %></p>
<% returnedItems.map(post => { %>
<h1><%= post.title %></h1>
<p>
<%= `${post.content.substr(0, 100)} ...` %>
Read More
</p>
<% }); %> <%- include('partials/footer'); %>
When I console log the array length returned from my database - right after post.save() - the length is zero. So, I'm not sure why this is happening. It could have something to do with asynchronous code, but I wrote another app earlier that used the same type of code seen here without a problem.
Edit: I fixed this with async-await using this syntax:
app.post('/compose', async(req, res) => {
const post = new Post({
title: req.body.postTitle,
content: req.body.postBody
});
await post.save();
res.redirect('/');
});

Why is my variable undefined in the template?

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 })

how to loop a collections inside a database and pull element from it

I am trying to extract data from the collection that is in my database, by looping, but without success.
can anyone know why i had this error?
.............................................................................
var express= require("express");
app= express();
var blogPostSchema = new mongoose.Schema({
title: String,
image: String,
description: String,
});
module.exports = mongoose.model("blogPost", blogPostSchema);
var blogPost = require("./models/blogPost");
//INDEX - show all blogPosts
app.get("/", function(req, res){
// Get all blogPost from DB
blogPost.find({}, function(err, allBlogPosts){
if(err){
console.log(err);
} else {
res.render("/",{blogposts:allBlogPosts});
}
});
});
<% blogposts.find().forEach(function(blogPost){ %>
<img src="<%= blogPost.image %>" alt="image">
<% }); %>
TypeError: /workspace/BeProgrammer/views/index.ejs:21
19|
20|
>> 21| <% blogPost.find().forEach(function(blogPost){ %>
22| <section class="blog-list px-3 py-5 p-md-5">
blogPost.find(...).forEach is not a function

Categories

Resources