I am making a user management system where the admin can login and add user details into an array called data and render it in the form of a table.There is a front-end form for the same purpose.
The problem is, I am able to take information from the the front-end from and push it to the array but not able to render in that table.
This is my user schema:
const userSchema= new mongoose.Schema({
email: String,
password: String,
data: [{
name: String,
emailAdd: String,
phone: Number,
}]
});
This is the post route for receiving user info and storing it in the array.
app.post("/add_user",function(req,res){
const userId=req.body.id;
User.findOne({userId}, function(err, foundUser) {
if (err) {
console.log(err);
} else {
if (foundUser) {
foundUser.data.push({
name:req.body.fname,
emailAdd:req.body.emailadd,
phone:req.body.phone
});
foundUser.save(function() {
res.redirect("/database");
});
// console.log(foundUser);
}
}
});
})
This is the get route for passing the object to front end:
app.get("/database", function(req, res) {
const userId=req.body.id;
if(req.isAuthenticated()){
User.find({ _id:userId,"data": {$ne: null}}, function(err, foundUser) {
if (err) {
console.log(err);
} else {
res.render("database", { newUser: foundUser });
}
});
}else{
res.redirect("/");
}
});
There is a database.ejs page containing the table where I need to render it:
<table class="list" id="employeeList">
<thead>
<tr>
<th>Full Name</th>
<th>Email</th>
<th>Number</th>
</tr>
</thead>
<tbody>
<%newUser.forEach(function(user){ %>
<tr>
<td><%=user.data.name%></td>
<td><%=user.data.emailAdd%></td>
<td><%=user.data.phone%></td>
</tr>
<% }); %>
</tbody>
</table>
The table still remains empty even after adding the user.
(P.S: I am using passport for encryption and mongoDB as database)
.No errors are showing up hence I don't know where I am going wrong.
Any help will be appreciated!
Related
I have an issue trying to associate a particular order with a particular product. I am new to node.js, I want to add a product(be associated and be populated with an order) and be redirected to a page which shows all orders of products i created
created the product and order schema(not too sure about the other schema)...
This is my product model
var mongoose= require("mongoose");
var productSchema = new mongoose.Schema({
name:String,
brand:String,
price: Number,
image: String,
description:String,
featured: Boolean,
});
module.exports= mongoose.model("Product", productSchema);
This Is order model:
var mongoose = require("mongoose");
var orderSchema= new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
products:[
{
type: mongoose.Schema.Types.ObjectId,
ref:"Product", required:true
}
]
,
quantity :{type:Number, default:1}
});
module.exports=mongoose.model("Order",orderSchema);
I want this models to be associated together using the mongoose method, be populated and then appear on a route ("/order) for example. I am new to programming and as such the simplest answer would be appreciated.
Here is a small working example using Express.Js, in this example I created 3 models :
// Models
const productSchema = new mongoose.Schema({
name:String
});
var orderSchema= new mongoose.Schema({
products:[productSchema]
});
const clientSchema = new mongoose.Schema({
name: String,
order: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Order'
}
})
const Product = mongoose.model('Product', productSchema);
const Client = mongoose.model('Client', clientSchema);
const Order = mongoose.model('Order', orderSchema);
My orderSchema will embed the products ordered by my clients, I chose to store products as subdocuments because I will have only few, you could also choose to store references instead.
Note: I'a referencing only one order per Client, you could choose otherwise, and make the order field in the clientSchema in an array (order: [{ /* type...*/}])
In my controller I have 2 methods: one to create an order and the other to add a product to the order.
// Controller
const createOrder = (userId, productId) => {
Product.findOne({_id: productId}) // find a product
.exec()
.then(product => new Order({products: [product]}).save()) // save the products into the order
.then(order => Client.findOneAndUpdate({_id: userId}, {$set: {order: order}}).exec())// update the client document with the new order
.then(client => res.json(client)); // respond with json
// .catch(err => console.log(err))
}
const addToOrder = (userId, productId) => {
return Product.findOne({_id: productId}) // find the product
.exec()
.then(product => {
return Client.findOne({_id: userId})//find the client
.populate({ path: 'order', populate: { path: 'order.products' } })
.exec() //populate in order to access client.order.products
.then(client => {
client.order.products.push(product);
return client.order.save();
})
})
// .catch(err => console.log(err));
}
I know need two routes: one to render a table with all the available products and one to render a cart with the ordered items.
// Get all products
app.get('/products', function(req, res) {
Product.find({})
.exec()
.then(products => res.render('products.ejs', {allProducts: products}))
.catch(err => res.json({errors: err}));
});
// Order a product
app.get('/products/:productId/order', function(req, res) {
req.user = {id: ""} /* id of the client, or the logged in user if you're using passeport or some other auth manager */
Client.findOne({_id: req.user.id})
.exec()
.then(client => {
if(client.order) {
return addToOrder(client.id, req.params.productId)
.then(order => res.render('cart.ejs', {order: order}))// render cart with the order
} else {
return createOrder(client.id, req.params.productId)
.then(order => res.json('cart.ejs', {order: order}))
}
})
.catch(err => res.json({errors: err}));
})
I need two (rendered by my route handlers):
// /views/products.ejs
<div>
<table>
<% allProducts.forEach(function(product) { %>
<tr>
<th>name</th>
</tr>
<tr>
<td><%= product.name %></td>
<td><a href=<%=`/products/${product.id}/order`%>> Order </a> </td>
<tr>
<% }) %>
</table>
</div>
// views/cart.ejs
<div>
<table>
<% order.products.forEach(function(product) { %>
<tr>
<th>name</th>
</tr>
<tr>
<td><%= product.name %></td>
<tr>
<% }) %>
</table>
</div>
I hope this helps.
Edit 2
I've tried the following.
routes
// competition form details
router.get('/dashboard/users/forms/competition-form/:id', ensureAuthenticated, (req, res) => {
CompetitionForm.find(req.params.id, function(err, competition){
res.render('dashboard/users/forms/competition-form.hbs', {
pageTitle: 'Competition Form',
users: competition
});
});
});
// competition form details post
router.post('/dashboard/users/forms/competition-form/:id', (req, res) => {
CompetitionForm.findOneAndUpdate({ _id: req.params.id }, req.body, {upsert:true}, (err, competition) => {
if (err) {
console.log(`Error saving data: ${err}`);
return res.send('Error saving data');
}
res.redirect('/dashboard');
console.log(req.body);
});
});
input
<input type="text" class="form-control" name="schoolName" placeholder="Enter school name" value="{{competition.schoolName}}"
Still no luck.
Edit 1
So I have tested your example value="{{user.schoolName}}" with users: CompetitionForm in the route, however I get the field value from the user registration and not the CompetitionForm.
Here's what I have
user model
const express = require('express');
const mongoose = require('mongoose');
var app = express();
if (app.get('env') === 'production') {
mongoose.connect(process.env.MONGODB_URI, { useMongoClient: true });
} else {
mongoose.connect('mongodb://localhost/pol-development', { useMongoClient: true });
}
var db = mongoose.connection;
mongoose.Promise = global.Promise;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
console.log("Connection has been established");
});
var CompetitionFormSchema = mongoose.Schema({
schoolName: String,
competitionDate: String,
competitionTime: String,
competitionVenue: String,
competitionTotalOfStudents: Number,
competitionTotalParticipated: Number,
competitionTotalPersonnel: Number,
competitionJudge1Name: String,
competitionJudge1Telephone: String,
competitionJudge1Email: String,
competitionJudge2Name: String,
competitionJudge2Telephone: String,
competitionJudge2Email: String,
competitionJudge3Name: String,
competitionJudge3Telephone: String,
competitionJudge3Email: String,
// admin fields
competitionRequiredPhotos: Boolean,
competitionRequiredCertifications: Boolean
});
var CompetitionForm = module.exports = mongoose.model('CompetitionForm', CompetitionFormSchema);
route
router.get('/dashboard/users/forms/competition-form/:id', ensureAuthenticated, (req, res) => {
CompetitionForm.find(req.params.id, function(err, CompetitionForm){
res.render('dashboard/users/forms/competition-form.hbs', {
pageTitle: 'Competition Form',
users: CompetitionForm
});
});
});
and for the form
<form action="/dashboard/users/forms/competition-form/{{user.id}}" method="post">
<label for="schoolName">School Name <span style="color: red">*</span></label>
<input type="text" class="form-control" name="schoolName" placeholder="Enter school name" value="{{user.schoolName}}" required>
Original
I have a competition form and a collection called competitionforms
I have the form working using the following routes
// competition form details
router.get('/dashboard/users/forms/competition-form/:id', ensureAuthenticated, (req, res) => {
CompetitionForm.find(req.params.id, function(err, CompetitionForm){
res.render('dashboard/users/forms/competition-form.hbs', {
pageTitle: 'Competition Form',
user_id: req.params.id
});
});
});
// competition form details post
router.post('/dashboard/users/forms/competition-form/:id', (req, res) => {
CompetitionForm.findOneAndUpdate({ _id: req.params.id }, req.body, {upsert:true}, (err, competition) => {
if (err) {
console.log(`Error saving data: ${err}`);
return res.send('Error saving data');
}
res.redirect('/dashboard');
console.log(req.body);
});
});
Now I want to pass the form data so the user can see what they have entered should they go back to the form.
The form is using the users id
<form action="/dashboard/users/forms/competition-form/{{user_id}}" method="post">
So I have tried the following
{{competitionforms.user.schoolName}},
{{competitionforms.users.schoolName}},
{{users.competitionforms.schoolName}} and
{{user.competitionforms.schoolName}}
I'm not sure what other combination I can try here.
It's impossible to give you specifics without knowing what your template looks like but that is probably for the better since it appears there is a general misunderstanding of how Express renders the form from the template.
A very simplistic explanation is res.render takes a template and replaces any instances of specially formatted text, such as {{foo}}, with the values specified by the variable object as the second argument. So if that variable object had a foo property, that value would be used.
Example #1:
Template (template.hbs):
Hi {{name}}! Is {{favoriteColor}} your favorite color?
Express App:
res.render('template.hbs', { name: 'John', favoriteColor: 'green' });
Rendered Output:
Hi John! Is green your favorite color?
Example #2:
The provided variable object can also include embedded objects too!
Template (template.hbs):
Hi {{name.first}}! Is {{favorites.color}} your favorite color?
Express App:
res.render('template.hbs', { name: { first: 'John' }, favorites: { color: 'green' }});
Rendered Output:
Hi John! Is green your favorite color?
Bringing it back to your example, assuming your template looks something like the following:
Template (dashboard/users/forms/competition-form.hbs):
<form action="/dashboard/users/forms/competition-form/{{user.id}}" method="post">
<label>School: <input type="text" name="schoolName" value="{{user.schoolName}}" /></label>
Then the updated Express code would look like:
router.get('/dashboard/users/forms/competition-form/:id', ensureAuthenticated, (req, res) => {
CompetitionForm.find(req.params.id, function(err, competitionForm){
res.render('dashboard/users/forms/competition-form.hbs', {
pageTitle: 'Competition Form',
user: competitionForm
});
});
});
This assumes your document object (competitionForm) has a property of schoolName.
For further reading on using Mustache templates in Express, checkout:
http://expressjs.com/en/guide/using-template-engines.html
https://github.com/janl/mustache.js
Edit:
Based on your Edit #2:
routes
// competition form details
router.get('/dashboard/users/forms/competition-form/:id', ensureAuthenticated, (req, res) => {
CompetitionForm.find(req.params.id, function(err, competition) {
res.render('dashboard/users/forms/competition-form.hbs', {
pageTitle: 'Competition Form',
users: competition
});
});
});
input
<input type="text" class="form-control" name="schoolName" placeholder="Enter school name" value="{{users.schoolName}}"
The template object properties must match the variable object properties so they can be accessed: { pageTitle: '...', users: {...} } ==> users.schoolName
i have this problem sorting my object of data in my index of my blog app.
I have a blog app based on Express using ejs and mongoDB using mongoose.
What i want is sorting the results so the newest post starts at the top. At this moment it will show the first post at the top.
app.js / mongoose schema
blogSchema = new mongoose.Schema({
title: String,
image: String,
body: String,
created: {type: Date, default: Date.now}
});
var Blog = mongoose.model("Blog", blogSchema);
app.js / Index route
app.get("/blogs", (req, res)=>{
Blog.find({}, (err, blogs)=>{
if(err){
console.log("Error!");
console.log(err);
} else {
res.render("index", {blogs: blogs});
}
});
});
index.ejs foreach
<% blogs.forEach(function(blog){ %>
<img alt="img" src="<%= blog.image %>">
<%= blog.title %>
<span><%= blog.created.toDateString() %></span>
<p><%- blog.body.substring(0, 200) %>...</p>
Read More
<% }) %>
Does anyone have a clue how i can do this?
You can use the sort() method of Mongoose:
Blog.find((err, blogs) => {
if (err) {
console.log(err);
} else {
res.render("index", { blogs: blogs });
}
}).sort({ created: 'desc' });
I started to develop a little web site in NodeJS, with admin authentication based on https://github.com/DanialK/Simple-Authentication, it work very well.
I can create a user, login with it and see the private page (dashboard).
But I have a problem with my template (I'm using Nunjucks), when the admin come to his dashboard I just wan't to show :
logged as : 'admin_username'.
This is my code :
Model :
const UserSchema = new mongoose.Schema({
username: String,
email: String,
password: String,
salt: String,
hash: String
})
Model definition :
const User = mongoose.model('user', UserSchema)
My route :
router.route('/admin/dashboard', requiredAuthentication)
.get((req, res) => {
console.log("################ GET DASHBOARD ##################")
requiredAuthentication(req, res, function() {
User.find().then(user => {
res.render('admin/dashboard.njk', {user: user})
console.log(user)
}).catch(err => {
console.error(err)
})
})
})
So I send "user", should be used in my template :
{% extends "base/layout.njk" %}
{% block content %}
admin:dashboard page <br /><br /><br />
{% if sessionFlash.message %}
<div class="{{ sessionFlash.type }}">
{{ sessionFlash.message }}
</div>
{% endif %}
You are logged as : {{ user.username }}
{% endblock %}
With user.username I can't get the username.
With user only I get the entire document from the DB, username, email, salt, hash.
This is the result of the console.log(user) from the route :
[ { _id: 58c58ad8a5e54c00117ce85b,
username: 'test',
email: 'test',
salt: '/71BBVmr8E3b/HUz8L89IWLV7xM/vG9nvJRGzQYPw4dwR8GICr0kJtGs8dqwNzsMU7yki9aa2WM7C2NRxf/ausw+4kyiLojfugYzdrh+6obBq5HcZPZfQq+djwsTyyd+CDPJ/EmbUQyIL1yM7lRLfkhfrCIZ9P1mJZZM9fv4thw=',
hash: '��F\u0000\u000b ��a�\u001c|A˓P�N&��\u0010�5ajd�7{c �#�mQ����&��W�rW\'�+������\u0013����������N�4�y>/1��R\u001ca>���=U�u<9�T�o" \u000b�����Ʌ^�\u0004\u001f��\u0007�B`A�d���N#M$���',
__v: 0 } ]
Don't know if this is important, there is the two function used for authentication : requiredAuthentication and authenticate :
function authenticate(name, pass, fn) {
if (!module.parent) console.log('authenticating %s:%s', name, pass);
User.findOne({
username: name
},
function (err, user) {
if (user) {
if (err) return fn(new Error('cannot find user'));
hash(pass, user.salt, function (err, hash) {
if (err) return fn(err);
if (hash == user.hash) return fn(null, user);
fn(new Error('invalid password'));
});
} else {
return fn(new Error('cannot find user'));
}
});
}
function requiredAuthentication(req, res, next) {
console.log("#### ->REQUIREDAUTHENTICATION() ####")
if (req.session.user) {
console.log("#### AUTH NEXT() ####")
next();
} else {
console.log("#### AUTH DIE() ####")
req.session.sessionFlash = {
type: 'alert alert-success',
message: 'You can't access the dashboard'
}
res.redirect('/admin/account/login');
}
}
Thanks for helping me, if you wan't additional informations ask me.
Looks like that user object is actually an array with 1 item. You can tell by that leading [ in the console.log output. To fix the issue, you can either pass in user[0] to your render function, or add a for loop to your template in case you'll be grabbing multiple users later on.
Below is the code I have tried to update the values in mongoDB but it is not working and showing an error while I am trying to update the values.
The error which is coming is :
{
"name": "MongoError",
"message": "insertDocument :: caused by :: 11000 E11000 duplicate key error index: agastyaforonewaydevelopmentstaging.deviceinfos.$_id_ dup key: { : \"355537056685953\" }",
"index": 0,
"code": 11000,
"errmsg": "insertDocument :: caused by :: 11000 E11000 duplicate key error index: agastyaforonewaydevelopmentstaging.deviceinfos.$_id_ dup key: { : \"355537056685953\" }"
}
And the code is:
// mongoose.connect('mongodb://user:password#ds031671.mongolab.com:31671/oneway', function(err) {
if (err) {
console.log('connection error', err);
} else {
console.log('connection successful');
}
});
var deviceSchema = new mongoose.Schema({
_id: {
type: String,
unique: true
},
MobileNum: Number,
Fecode: String
})
var deviceinfo = mongoose.model('deviceinfo', deviceSchema);
// Device collection close
app.get('/feature', function(req, res) {
res.render('feature.ejs', {
user: req.user
});
});
app.get('/feature', function(req, res) {
res.render('feature.ejs');
});
app.post('/feature', function(req, res) {
// if(collection.findOne({_id:req.body.Imei}))
new deviceinfo({
_id: req.body.Imei,
MobileNum: req.body.Mobile,
Fecode: req.body.fecode
}).save(function(err, drd) {
if (err) res.json(err);
else
res.render('feature.ejs');
});
});
app.get('/fupdate', function(req, res) {
res.render('upfeature.ejs');
});
app.post('/fupdate', function(req, res) {
// if(collection.findOne({_id:req.body.Imei}))
new deviceinfo({
_id: req.body.Imei,
MobileNum: req.body.Mobile,
Fecode: req.body.fecode
}).update(function(err, drd) {
if (err) res.json(err);
else
res.render('feature.ejs');
});
});
How to rectify the error?
Any help would be appreciated.
Please avoid updating document using new object model of existing _id
Instead you can update a document by passing _id as query string
app.post('/fupdate/:Imei', function(req, res) {
deviceinfo.findById(req.params.Imei, function(err, device) {
if (err)
res.send(err);
device.MobileNum = req.body.Mobile;
device.Fecode = req.body.fecode;
device.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'device updated!' });
});
});
});
Check your error, it clearly states
duplicate key error index:
Which means you are trying to duplicate an index(e.g. have it twice), and you can't have that.
I checked out your code again, and i noticed you have
app.get('/feature'
Twice. Is there any reason for that?
PS: MongoDB says you have the same ID twice, which probably means there's something wrong in your front-end(back-end seems fine), and you're sending the same value.
Edit: If you want to update a record, you have to use the update method of Mongoose. Here's what the docs have to say about it http://mongoosejs.com/docs/2.7.x/docs/updating-documents.html
Otherwise you're just trying to create a new record with the same data.
#Raja
How to change the edit button so that while clicking on that it should select the id.
The edit option I have given as a link which open a page on click.Below is the code :
<table class="table table-bordered">
<tbody>
<tr>
<td><%= drd._id %></td>
<td><%= drd.MobileNum %></td>
<td><%= drd.Fecode %></td>
<td> <a class="button" href="/fupdate"><img src="/images/edit.png" width="20" height="20"></a></td>
</tr>
</tbody>
</table>