Sending through variables in `res.render` that are conditionally empty - javascript

I'm trying to send through multiple variables into a res.render but I'm unsure of how to do it without an undefined error. Either one or the other will have an object to pass through but never both at the same time. Here's my current code that will give an undefined error.
app.get('/', async (req, res) => {
if (req.query.search) {
const search = req.query.search
const regex = new RegExp(search, 'i')
const searchedblogposts = await BlogPost.find({title: {$regex: regex}})
console.log(searchedblogposts)
} else {
const blogposts = await BlogPost.find({})
}
res.render('index', {
blogposts,
searchedblogposts
})
})

Well, this is because one of blogPosts or searchBlogPosts remains undefined at any point of time and you're passing both in res.render . What you can do is this:
app.get('/', async (req, res) => {
let blogPosts;
if (req.query.search) {
const search = req.query.search
const regex = new RegExp(search, 'i')
blogPosts = await BlogPost.find({title: {$regex: regex}})
} else {
blogposts = await BlogPost.find({})
}
res.render('index', {
blogposts,
})
})
OR this:
app.get('/', async (req, res) => {
const blogPosts = req.query.search? await BlogPost.find({title: {$regex: new RegExp(req.query.search, 'i')}})
: await BlogPost.find({})
res.render('index', {
blogposts,
})
})

Related

Route.post() requires a callback function but got a [object Undefined] In ExpressJs

I'm aware this question has been asked before. I tried all the solutions that were provided but still I'm stuck. Please have a look at my code:
1) ReviewController.js
exports.setTourUserIds = (req, res, next) => {
// allow nested route
if (!req.body.tour) req.body.tour = req.params.tourId
if (!req.body.user) req.body.user = req.user.id
next()
}
exports.createReview = handlerFactory.createOne(Review)
exports.updateReview = handlerFactory.updateOne(Review)
exports.deleteReview = handlerFactory.deleteOne(Review)
2) ReviewRoute.js
let express = require('express')
let Router = express.Router({ mergeParams: true })
let reviewController = require('../controllers/reviewController')
let authController = require('../controllers/authController')
Router
.route('/')
.get(reviewController.getAllReviews)
.post(authController.protect,
authController.restrictTo('user'),
reviewController.setTourUserIds,
reviewController.createReview)
Router
.route('/:id')
.get(authController.protect, reviewController.getReview)
.patch(reviewController.updateReview)
.delete(reviewController.deleteReview)
module.exports = Router
3) handlerFactory.js
exports.createOne = Model => catchAsync(async (req, res, next) => {
let doc = await Model.createOne(req.body)
if (!doc) {
return next(new AppError('No document found with that ID', 404))
}
res.status(201).json({
status: 'success!',
data: { doc }
})
})
Please change your code from
exports.createReview = handlerFactory.createOne(Review)
exports.updateReview = handlerFactory.updateOne(Review)
exports.deleteReview = handlerFactory.deleteOne(Review)
to
exports.createReview = () => { handlerFactory.createOne(Review)}
exports.updateReview = () => { handlerFactory.updateOne(Review) }
exports.deleteReview = () => { handlerFactory.deleteOne(Review) }
You should pass a function to the router
Check following syntax:
Router
.route('/:id').post(function(){})

I can not send a specific data (JavaScript)

I'm having trouble with my code I can not recover this data my array. Do you have an idea? Thank you.
I can not get my data inside my array outside my loop..
Node.js/Mongoose :
Controllers :
exports.newsfeedContent = async (req, res, next) => {
try {
const decoded = req.decoded;
await newsfeedContentQueries(decoded, req, res, next);
} catch (e) {
console.log(['erreur'],e)
}
};
Queries :
exports.newsfeedContentQueries = function (decoded, req, res, next) {
const sub = decoded;
User.findOne({
'_id': sub
}).exec().then((user) => {
User.findOne({
'amis': user.amis
}).exec()
.then((user) => {
let tab = []
for (let index = 0; index < user.amis.length; index++) {
MessageUser.find({'userID': user.amis[index]}).exec().then((UserMessage)=>{
for (let index2 = 0; index2 < UserMessage.length; index2++) {
tab.push(UserMessage[index2].message) //<= The data I want to recover.
console.log(tab); // <= Here my array to all the data.
}
})
}
console.log(tab) // <= Here my array sends me = []
req.newsfeedUser = tab // <= what I would like to do, but my array is empty..
next()
})
}).catch((err) => {
console.log(err);
});
};
User.js :
router.get('/newsfeed', verify, newsfeedContent, (req, res) => {
console.log(req.newsfeedUser); // Here my array sends me = []
});
I successful .. I did not know that when I supply a array as a value, it would be automatically by mongoose iterated.
exports.newsfeedContentQueries = async function (decoded, req, res, next) {
const user = await User.findOne({
'_id': decoded
}).exec().then((data) => {
return data
});
const messageList = await MessageUser.find({
'userID': user.amis
}).exec().then((data) => {
return data
});
res.json(messageList);
};

Export the particular variable of function to another file

I have a query, that is how I can send "userURL" variable from below file(imageController.js) to another file(contactController.js). and one thing I want to send only "userURL" variable not the whole function "resize". I tried a lot to solve this issue by using "module.exports" but the problem I got is that "module.exports" sending the whole function "resize" not the "userURL" variable. now in second file "contactController.js" where i have mentioned {userURL} in console.log but it's printing only "your result undefined". I just want to export userURL from first file imageController.js to second file "contactController.js".
imageController.js
exports.resize = async (req, res, next) => {
if(!req.file){
next()
return
}
const extension = req.file.mimetype.split('/')[1]
req.body.userFile = `${uuid.v4()}.${extension}`
const photo = await jimp.read(req.file.buffer)
await photo.resize(500, jimp.AUTO)
await photo.write(`./public/uploads/${req.body.userFile}`)
const userimg = photo;
console.log(`./public/uploads/${req.body.userFile}`)
cloudinary.config({
cloud_name: 'katal',
api_key: process.env.API_KEY,
api_secret: process.env.API_SECRET
});
cloudinary.v2.uploader.upload(`./public/uploads/${req.body.userFile}`,{
transformation: { width:100, height:100}}, function(error, result) {
console.log('please show result\t' +JSON.stringify(result))
const userURL ='vikivivki'
res.send(result.secure_url)
console.log(result.secure_url)
})
}
contactController.js
const mongoose = require('mongoose')
const Contact = mongoose.model('Contact')
const moment = require('moment-timezone')
const {userURL} = require('./imageController')
exports.contactForm = (req, res) => {
res.render('contact')
}
exports.usermessage = async(req, res) => {
req.body.name = req.body.name
req.body.email = req.body.email
req.body.message = req.body.message
const ind = moment.tz(Date.now(), "Asia/Calcutta")
const newContact = new Contact(req.body)
await newContact.save()
console.log('your result',userURL)
let showResult1 = JSON.stringify(newContact)
let showResult = JSON.parse(showResult1)
res.send(showResult.message)
}
You need to export items you need access to
exports.userURL ='vikivivki'; //exporting here along with rezise as well
file imageController.js
//imageController.js
exports.userURL ='vikivivki'; //exporting here along with rezise as well
exports.resize = async (req, res, next) => {
if(!req.file){
next()
return
}
const extension = req.file.mimetype.split('/')[1]
req.body.userFile = `${uuid.v4()}.${extension}`
const photo = await jimp.read(req.file.buffer)
await photo.resize(500, jimp.AUTO)
await photo.write(`./public/uploads/${req.body.userFile}`)
const userimg = photo;
console.log(`./public/uploads/${req.body.userFile}`)
cloudinary.config({
cloud_name: 'katal',
api_key: process.env.API_KEY,
api_secret: process.env.API_SECRET
});
cloudinary.v2.uploader.upload(`./public/uploads/${req.body.userFile}`,{
transformation: { width:100, height:100}}, function(error, result) {
console.log('please show result\t' +JSON.stringify(result))
const userURL ='vikivivki'
res.send(result.secure_url)
console.log(result.secure_url)
})
}
In your contactController.js
//contactController.js
const mongoose = require('mongoose')
const Contact = mongoose.model('Contact')
const moment = require('moment-timezone')
const {userURL} = require('./imageController'); // Please have a check on location if they are in the same directory
exports.contactForm = (req, res) => {
res.render('contact')
}
exports.usermessage = async(req, res) => {
req.body.name = req.body.name
req.body.email = req.body.email
req.body.message = req.body.message
const ind = moment.tz(Date.now(), "Asia/Calcutta")
const newContact = new Contact(req.body)
await newContact.save()
console.log('your result',userURL)
let showResult1 = JSON.stringify(newContact)
let showResult = JSON.parse(showResult1)
res.send(showResult.message)
}

How do I make hbs render an array from a callback function?

Currently I have axios and cheerio return data from a webpage. I then setup express to setup a few views. I double checked my index.hbs and it include {{data}} inside the body. This should allow the page to render the text from the index render data: dealss . Am I missing anything ? The dealss obj holds 4 different objects that I can access.
getdeals(result => console.log(result.totaldeals[0].date))
This returns [ 09/04/2019/ ] in the console.
const path = require('path')
const express = require('express')
const hbs = require('hbs')
const axios = require('axios');
const cheerio = require('cheerio');
const app = express()
// Define paths for express config
const publicDirPath = path.join(__dirname, '../public')
const viewsPath = path.join(__dirname, '../templates/views')
const partialsPath = path.join(__dirname, '../templates/partials')
// Setup handlebars engine and views location
app.set('view engine', 'hbs')
app.set('views', viewsPath)
hbs.registerPartials(partialsPath)
// Setup static directory to serve
app.use(express.static(publicDirPath))
// Views
app.get('', (req, res) => {
res.render('index', {
title: 'ClearVision',
data: dealss,
name: 'Chris'
})
})
app.get('/about', (req, res) => {
res.render('about', {
title: 'ClearVision - About Us',
header: 'About Us',
name: 'Chris'
})
})
app.get('/help', (req, res) => {
res.render('help', {
title: 'ClearVision - Help',
helptext: 'Please contact x for help.',
name: 'Chris'
})
})
app.get('/weather', (req, res) => {
res.send({
forecast: 'It is sunny.',
location: 'x, Ca'
})
})
app.listen(1337, () => {
console.log('Server is currently running on port 1337.')
})
const url = 'https://abcdef.com/';
axios.defaults.withCredentials = true
// Get the deals
const getdeals = (callback) => {
axios(url, {
headers: {
Cookie: "x=xx;"
}
})
.then(response => {
const html = response.data;
const $ = cheerio.load(html);
// Deals Page
const statsTable = $('tbody > tr');
const totaldeals = [];
// Loop Table for data in each row
statsTable.each(function () {
const nwline = "\n"
let date = $(this).find('td:nth-child(1)').text()
let bodydeals = $(this).find('td:nth-child(2)').text()
let newdeal = $(this).find('td:nth-child(3)').text()
let revdeal = $(this).find('td:nth-child(4)').text()
let monthlydealrev = $(this).find('td:nth-child(5)').text()
// Clear /n
if (date.includes(nwline)) {
date = date.toString().replace("\n", ""),
date = date.toString().replace("\n", "")
}
// Clear /n
if (bodydeals.includes(nwline)) {
bodydeals = bodydeals.toString().replace("\n", ""),
bodydeals = bodydeals.toString().replace("\n", ""),
bodydeals = bodydeals.toString().replace("\n", "")
}
// Clear /n
if (newdeal.includes(nwline)) {
newdeal = newdeal.toString().replace("\n", ""),
newdeal = newdeal.toString().replace("\n", ""),
newdeal = newdeal.toString().replace("\n", "")
}
// Clear /n
if (revdeal.includes(nwline)) {
revdeal = revdeal.toString().replace("\n", ""),
revdeal = revdeal.toString().replace("\n", ""),
revdeal = revdeal.toString().replace("\n", "")
}
// Clear /n (lookup jquery table functions)
if (monthlydealrev.includes(nwline)) {
monthlydealrev = monthlydealrev.toString().replace("\n", ""),
monthlydealrev = monthlydealrev.toString().replace("\n", ""),
monthlydealrev = monthlydealrev.toString().replace("\n", "")
}
totaldeals.push({
date,
bodydeals,
newdeal,
revdeal,
monthlydealrev
})
})
callback({
totaldeals
})
//console.log(totaldeals[1].date)
})
.catch(console.error);
}
function newFunction() {[getdeals(result => console.log(result.totaldeals))]}
I added a data: dealss under the res.render for the index. I also checked the index.hbs which has {{data}} in there. Shouldn't this just add the text to the screen?
Any ideas on how to print it to the view?
You just need to pass it as a variable to your hbs file:
app.get('', (req, res) => {
getdeals(result => {
res.render('index', {
title: 'ClearVision',
data: result, // or result.totaldeals depending
name: 'Chris' // on what you really mean
})
});
})
Improvements
If you rewrite getdeals() to return a Promise instead of accepting a callback you can use async/await:
const getdeals = () => {
// NOTE THIS CHANGE, return axios promise:
return axios(url, {
/* ... */
})
.then(response => {
/* .. */
statsTable.each(function () {
/* .. */
})
return totaldeals; // NOTE we return the result instead
// of calling a callback. This will
// return a resolved Promise
})
// Don't catch here, your request will hang if an error occurs
}
Now with the change above (return axios and return the result) we can rewrite the route as:
app.get('', async (req, res, next) => { // must have async keyword!
try {
let result = await getdeals();
res.render('index', {
title: 'ClearVision',
data: result, // or result.totaldeals depending
name: 'Chris' // on what you really mean
})
}
catch (err) {
console.log(err);
next(err); // this will close the request socket
}
})

How to convert string "req.body" to data (function)?

I make a function checkCompanyPermit with paramater companyIdSource and array allowed.
Example:
companyIdSouce: "req.body.companyId", "req.params.companyId"...
allowed: "user", "admin"...
With parameter companyIdSource as string, I want to convert it to data. It's worked if I use eval(companyIdSource) but it's bad. How can I do another?
I try use Function("return " + companyIdSource)() but it return an error: req is not defined.
const checkCompanyPermit = (companyIdSource, ...allowed) => {
return async (req, res, next) => {
try {
const companyId = eval(companyIdSource) //Bad code, change another code
const company = await Company.findById(companyId)
//... some code
} catch (error) {
next(error)
}
}
}
checkCompanyPermit("req.body.companyId", "manager")
Since you already have access to the req object in your middleware, there is no need to pass the full string representation for req.body.companyId, just the property you need to check will suffice. Use the bracket notation to access the value from req.body object i.e.
const checkCompanyPermit = (companyIdSource, allowed) => {
return async (req, res, next) => {
try {
const companyId = req.body[companyIdSource]
const company = await Company.findById(companyId)
//... some code
} catch (error) {
next(error)
}
}
}
checkCompanyPermit("companyId", "manager")
It's Working For You.
const ObjectId = require('mongodb').ObjectId;
const checkCompanyPermit = (companyIdSource, ...allowed) => {
return async (req, res, next) => {
try {
const companyId = ObjectId('companyIdSource') //Replace here new code
const company = await Company.findById(companyId)
//... some code
} catch (error) {
next(error)
}
}
}
checkCompanyPermit("req.body.companyId", "manager")

Categories

Resources