I'm new to express and pug so forgive me if this is a noob question but how do I pass the array I created in one function to the route that will render the pug template. I ultimately want to loop though the array and render it as a table.
My code - first I create the array from the data received from a file with the lodash map method. *EDIT - added full code structure -
fs.readFile(file, 'utf8', function (err, data) {
if (err) {
console.log('Error: ' + err);
return;
}
var data = JSON.parse(data);
var newEventList = data.events.map(events => ({
id: events.id ,
name: events.name ,
venue: events.place.name ,
address: events.place.location.street + " " +
events.place.location.city + " " + events.place.location.zip ,
coverPicture: events.coverPicture ,
description: events.description ,
startTime: events.startTime ,
endTime: events.endTime
}));
});
So now I have an array of objects called newEventList.
My route for pug is
app.get('/', function (req, res, newEventList) {
res.render('index', { title: 'Hey', message: 'Hello there!',
newEventList
})
})
I added title and message to test my pug template.
in my Pug Template I have
h1= message
p= newEventList
but in the paragraph that is rendered I get a long error message -
function next(err) { // signal to exit route if (err && err === 'route') { return done(); } // signal to exit router if (err && err === 'router') { return done(err) } var layer = stack[idx++]; if (!layer) { return done(err); } if (layer.method && layer.method !== method) { return next(err); } if (err) { layer.handle_error(err, req, res, next); } else { layer.handle_request(req, res, next); } }
What am I doing wrong please?
From your route definition's callback, remove or rename newEventList as your third param.
In your example, newEventList is getting assigned to the done/next callback. Hence you're seeing a function being printed in your paragraph.
var newEventList = // Whatever value;
app.get('/', function (req, res) {
res.render('index', { title: 'Hey', message: 'Hello there!',
newEventList
})
})
Related
I get error: "UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client",
guessing that the problem is with promises, but I don't understand how to fix it.
How do I fix my code to avoid this error, but keep the logic and work with the database?
router.post("/addNote", (req, res) => {
let currentTime = new Date();
currentTime.setUTCHours(currentTime.getUTCHours() + 3);
const post = new PostModel({
title: req.body.inputHeader,
text: req.body.inputText,
author: req.body.author,
createdAt: currentTime
});
post.save().then(() => {
res.json({status: "saved"});
})});
router.get("/getNotes", (req, res) => {
PostModel.find().sort({createdAt: 'descending'}).then( (err, notes) => {
if (err)
res.json(err);
res.json(notes);
});
});
router.delete("/deleteNote/:id", (req, res) => {
PostModel.deleteOne(
{
_id: req.params.id
}
).then((notes) => {
if (notes)
res.json({status: "deleted"});
res.json({status: "error while deleting"});
});
});
router.put("/updateNote/:id", (req, res) => {
PostModel.findByIdAndUpdate(
req.params.id,
{
$set: req.body
},
err => {
if (err)
res.send(err);
res.send({status: "updated"})
}
).then((notes) => {
if (notes)
res.json({status: "update"});
res.json({status: "error while updating"});
});
});
router.get("/getNote", (req, res) => {
PostModel.findOne({ _id: req.params.id}).then(post => {
if (!post){
res.send({error: "not found"});
} else {
res.json(post)
}
});
});
router.post("/authorize", (req, res) => {
// bcrypt.hash ("", saltRounds, (err, hash) => {
// console.log(hash);
// });
let resultAuthorization = false;
if (req.body.login === authorization.login) {
resultAuthorization = bcrypt.compareSync(req.body.password, authorization.password);
}
if (resultAuthorization)
res.json({statusAuthorization: "correct"});
res.json({statusAuthorization: "incorrect"});
});
module.exports = router;
The problem is that you are calling res.json several times in one handler. When calling it a second time a response has already been sent so you can not send another response.
As tkausl already pointed out you are missing elses so that res.json is being called once.
You need to change your handlers similar to the /getNote handler.
The handler for the endpoint deleteNode/:id for example has to be changed to this:
router.delete("/deleteNote/:id", (req, res) => {
PostModel.deleteOne(
{
_id: req.params.id
}
).then((notes) => {
if (notes)
res.json({status: "deleted"});
else
res.json({status: "error while deleting"});
});
});
This else also needs to be added in /getNotes and /authorize.
The reason is you're trying to send a response more than once. Once the response is returned, if the program sends a response again, this error occurs.
The reason for the problem is that you do not return the current function after the if condition.
Let me explain with some codes
router.get("/getNotes", (req, res) => {
PostModel.find().sort({createdAt: 'descending'}).then( (err, notes) => {
if (err) {
res.json(err);
console.log('We encountered an error and sent the error as a response. But our function still continue...');
}
res.json(notes);
console.log('We tried to sent successfull response but function still continue');
});
});
So after the response, you should end the function or make sure that you do not call any other response function in the ongoing code stream/flow.
Lets fix your code.
router.get("/getNotes", (req, res) => {
PostModel.find().sort({createdAt: 'descending'}).then( (err, notes) => {
if (err) {
return res.json(err);
// It is not will be continued because the function returned with response.
}
return res.json(notes);
console.log('No console output')// It is will not be called because function returned.
});
});
I got an error like that: uncaughtException TypeError: cb is not a function
I think this error is caused by callback error but I don't know why I have this error.
app.put('/badge/student_badge/:id', upload, (req, res, next) => {
const name = req.body.name;
let data = {
name: name
}
badger.updatePersonBadge({
id: req.params.id
}, data, (err) => {
if (err) return next(err);
res.status(201).json({
message: 'Post updated successfully!'
});
});
});
function updatePersonBadge(options, cb) {
schemas.badger.then(b => {
b.findById({
_id: options.id
}, (err, resp) => {
if (err) return cb(err);
if (!resp) return cb("no badge found");
name = options.name;
title = resp.title;
points = resp.points;
updateBadge(name, title, points, cb);
cb(null, resp);
})
})
}
function updateBadge(name, title, points, cb) {
const dateCreated = new Date(),
dateUpdated = dateCreated;
registerSchemas.personModel.then(p => {
p.findOneAndUpdate({
name: name
}, {
$push: {
badges: [{
title: title,
points: points,
dateCreated: dateCreated,
dateUpdated: dateUpdated
}]
}
}, (err, resp) => {
if (err) return cb(err);
if (!resp) return cb("no person found");
})
})
}
You are not passing the cb argument and if it's optional (at least seems it should be) the function misses an if statement:
updatePersonBadge(options, cb) { // << cb (callback) argument expected
// ...
cb(null, resp); // cb called therefore not optional (Its needed)
If you use it like updatePersonBadge(aaa) instead of updatePersonBadge(aaa, myCallbackFn) the cb() is undefined but expressed as a function call - that does not exist.
You could instead make it optional (if that's the case):
//...
if(cb) cb(null, resp); // call the cb function if cb argument exists
or if you want to be more specific:
//...
if(cb && typeof cb === 'function') cb(null, resp);
instead of passing a function you're passing data:
badger.updatePersonBadge({}, data, errFn);
I assume this is the place from where you are calling updatePersonBadge. IF yes, then you are passing callback as a third argument, You have to use them correctly.
badger.updatePersonBadge(
{
id: req.params.id
},
data,
(err) => {
if (err) return next(err);
res.status(201).json({
message: 'Post updated successfully!'
});
});
In the example the problem is parameter mismatch, In place of callback you send data
app.put('/badge/student_badge/:id', upload, (req, res, next) => {
const name = req.body.name;
let data = {
name: name
}
badger.updatePersonBadge({id:req.params.id}, data, (err)=>{. -- three arguments passed
if (err) return next(err);
res.status(201).json({
message: 'Post updated successfully!'
});
});
});
Where in function definition you have only 2 parameters defined.
where it should be 3 parameters / that particular scenario should be validated.
I have created an api using nodejs, express and mongodb. I am fetching data now without sending any query. But in my frontend I have an input where the user can search for a recipe. So for example if a user types "Today" i should get response related to today only. How to check that in db and retrieve data?
module.exports = function(app, db) {
app.get("/dates/", (req, res) => {
db
.collection("dates")
.find()
.toArray((err, item) => {
if (err) {
res.send({ error: "An error has occured" });
} else {
res.send(item);
}
});
});
While making the api call , pass the dish as query parameter
For example '/recipes/?dish="Pizza" '
and in the express use the following.
module.exports = function(app, db) {
app.get("/recipes/", (req, res) => {
let queryDish = req.query.dish; // assuming /recipes/?dish="Pizza"
let query = { 'title' : { '$regex' : queryDish, '$options' : 'i' } };
db
.collection("recipes")
.find(query)
.toArray((err, item) => {
if (err) {
res.send({ error: "An error has occured" });
} else {
res.send(item);
}
});
});
I'm using mongodb for pretty much everything in my node.js application, and now i want create a restful application, so, i did that:
I'm trying to do just the get method, for now:
restApi.js:
var restAPI = {
get: function(method, model, sort, limit, options) {
if (method !== 'get') {
return;
}
model.find(options).sort(sort).limit(3).exec(function (error, result) {
if (error) {
return error;
} else {
return result;
}
});
},
};
And now i can require this in my route:
var restApi = require('restApi');
and use like this:
app.get('/', function(req, res, next) {
var result = restAPI.get('get', Event, 'date', 3, {'isActive': true});
res.render('/', {
result: result
});
});
Is not working, the result is undefined. Why??
How can i transform this in a async function with callback? This is possible?
Thanks! :)
You're not returning anything from restApi.get. If you're using mongoose, you could return a Promise easily enough:
var restAPI = {
get: function(method, model, sort, limit, options) {
if (method !== 'get') {
return;
}
return model.find(options).sort(sort).limit(3).exec();
},
};
Then you can use it like this:
app.get('/', function(req, res, next) {
restAPI.get('get', Event, 'date', 3, {'isActive': true}).then( function ( result ) {
res.render('/', {
result: result
});
}).catch( error ) {
// Render error page and log error
});
});
It is because your model is async. You have to pass callbacks.
Using async way is better because it is not blocking your application while waiting for response.
Example on your case:
restApi.js:
var restAPI = {
get: function(method, model, sort, limit, options, cb) {
if (method !== 'get') {
return cb("Method must be GET");
}
model.find(options).sort(sort).limit(3).exec(function (error, result) {
if (error) {
return cb(error);
} else {
return cb(null, result);
}
});
},
};
And now i can require this in my route:
var restApi = require('restApi');
and use like this:
app.get('/', function(req, res, next) {
restAPI.get('get', Event, 'date', 3, {'isActive': true}, function(err, result){
if(err)
return res.render("Error:" + err)
res.render('/', {
result: result
});
});
});
I've added cb argument to your REST API function so it is called when model async operation is done.
Router handler passes it's callback and prints output when operation is finished.
Im new to js/nodejs/express, and on my own tried to structure my file in an MVC like pattern
The problem is the console.log (at routes.js, the most important) returns undefined, while the second one returns the real data, and is executed by node respectively as well, How would I return that data in an async manner from my model to the route?
In my server.js
require('./modules/pos/routes')(app);
require('./modules/pos/models/inventory')(app);
In my routes.js
module.exports = function(app) {
Inventory = require('./models/inventory')(app);
app.get('/poss', function(req, res) {
var result = Inventory.get();
console.log('result1 is',result); // !
res.end(JSON.stringify(result));
});
}
In my inventory.js
module.exports = function(app) {
return {
get : function() {
var res;
app.conn.query('SELECT * FROM users', function(err, rows) {
res = JSON.stringify({users : rows});
console.log("result is ",res); // !
return res;
});
}
}
}
P.S executing node server in the terminal, and browsing to localhost:8000 gives
result1 is undefined
result is {"users":[{"id":1, "username": ...blah..
Your first console.log is executed before the second. And the get method doesn't return anything because the method that returns is the one inside the get. In order to make your method async add a callback, like this:
// inventory.js
module.exports = function(app) {
return {
get : function(cb) {
app.conn.query('SELECT * FROM users', function(err, rows){
if (err) {
return cb(err);
}
res = JSON.stringify({users : rows});
console.log("result is ", res);
cb(null, res)
});
}
};
};
// routes.js
module.exports = function(app) {
var Inventory = require('./models/inventory')(app);
app.get('/poss', function(req, res) {
Inventory.get(function (err, result) {
if (err) {
// do something else in case of error
return;
}
res.end(result); // you don't need to use json stringify here cause the result is serialized
});
});
}