implement voting system using node.js, mongodb and ejs - node.js

I'm pretty new to node.JS and ejs. I have searched how to implement real-time voting system like Stackoverflow voting using the mentioned technology. But I don't have any Idea how to do it.
here is my front-end code:
<% for (var i = 0; i < gamePasses.length; i++) {%>
<form dir="ltr">
<tr>
<td>
<%= i + 1 %>
</td>
<td>
<%= gamePasses[i].teamName %>
</td>
<td>
<%= gamePasses[i].password %>
</td>
<td>
<%= gamePasses[i].votes %>
</td>
<td onclick="vote('<%= gamePasses[i].password %>')">
<i class="material-icons">
thumb_up
</i>
</td>
</tr>
</form>
<% } %>
<script>
function vote(pass) {
$.post('/user/vote/' + pass)
}
function passSubmit() {
$.post('/user/gamePassword', {
gamePassword: $('#password').val()
}).done(() => {
window.location.assign('/user/scoreboard')
})
}
</script>
back-end code:
uter.post('/vote/:gamePassword', (req, res) => {
gamePassword = req.params.gamePassword;
gamePassModel.find({password: gamePassword}, (err, result) => {
if (err) console.log(err)
else {
result.votes += 1
result.save((err) => {
if (err) console.log(err)
})
}
})
})
This code problems are:
Doesn't support real-time voting
each user can votes many times
I will be thankful if anyone could help me

For prohibit multiple vote from the same user, you can think something like this. Didn't test it but the logic should works.
uter.post('/vote/:gamePassword', (req, res) => {
gamePassword = req.params.gamePassword;
//you can retrieve the voter id the way you want (in this case I assumed the query string contains it)
let voterId = req.query.voterId
gamePassModel.find({password: gamePassword}, (err, result) => {
if (err) console.log(err)
else {
//votes in not a number anymore. Now it's an array of IDs, you have to change the model (in Mongoose, I suppose)
if(~result.votes.indexOf(voterId)) {
result.votes.push(voterId)
//I'm pretty sure you cannot call save() like you do on this object, but this is not part of the question here, check the mongoose docs
result.save((err) => {
if (err) res.json({error:err});
})
} else res.json({ error: "you already voted" });
}
})
})
Now when you want to get the total vote of something, you have to make a count query (still assuming mongodb/mongoose https://mongoosejs.com/docs/api.html#model_Model.count)

Related

Show MongoDB Query Result On ejs page

I have a router which returns a specefic user's information based on the unique Object_id from MongoDB. This works fine, and I get the correct results, but they are returned on a "blank" page as a JSON object. I want to simply fetch the result and render them on my ejs page. Here are my route:
//Here are my router.js:
router.get('/user/get:id', function (req, res) {
MongoClient.connect(DBUri,{useUnifiedTopology: true }, function (err, db) {
let dbo = db.db(DBName);
const query = {_id: objectId(req.params.id)}
dbo.collection("Users").find(query).toArray(function(err, resultTasks) {
if (err) throw err;
res.send(resultTasks)
db.close();
});
});
});
//Here are my file.ejs:
<div class="card" v-for="post in filteredList">
<a v-bind:href="'/user/get' + post.id">{{ post.name }}</a>
</div>
Im still new so I know this is properly basic. I guess I have to change the res.send to something else, but now sure how.
You need to loop over resultTasks in your ejs template, something like:
<% resultTasks.forEach((post) => { %>
<div class="card" v-for="post in filteredList">
<a v-bind:href="/user/get/<%= post.id %>"><%= post.name %></a>
</div>
<%}); %>
Also, you probably need to change send in your endpoint with
dbo.collection("Users").find(query).toArray(function(err, resultTasks) {
if (err) throw err;
db.close();
res.render('<path of your ejs file>', {
resultTasks: resultTasks, // pass data from the server to the view
});
});

Without err argument I get null

I am learning Express with Mongoose and I am rendering a page where I run a forEach on a list of "campgrounds" from a MongoDB. My understanding is that when running the .find function it is optional to pass the err argument and run an if statement. But when I remove the err argument and the if statement altogether I get a "cannot run forEach on null while when I add it back (no other changes) my code runs smoothly. Not a problem when I add it back but I'm trying to understand what's going on in the background. Thanks in advance!
App.js code
//Create the camgrounds route
app.get("/campgrounds", function(req, res) {
//Get Campgrounds from DB
Campground.find({}, function(err, dbCampgrounds) {
//check for error
if (err) {
console.log(err);
//render the campgrounds page passing in the campground info from the db
} else {
res.render("campgrounds", {
renderCampGround: dbCampgrounds
});
}
});
});
And ejs file code
<div class="row">
<% renderCampGround.forEach(function(x){ %>
<div class="col-med-3 col-sm-6">
<div class="thumbnail">
<img src="<%= x.image %>">
</div>
<div class="caption">
<h4 <%= x.name %>>
</div>
</div>
</div>
<% }); %>
</div>
You are using the callback function so, all callbacks in the Mongoose use the pattern callback(err, data). So, if an error occurs while executing the query the error parameters will contain the error document and data will be null. If the query runs successfully then the error parameter will be null. But it is important to notice that not finding a document is not an error.
If you do not specify callback function then API will return the variable of type Query. Have a look.
So, if you don't want to use callback function then it will look like this.
//Create the camgrounds route
app.get("/campgrounds", function(req, res){
var campgrounds = Campgrounds.find({});
//execute a query at later time
campgrounds.exec(function (err, data) {
if (err) {
console.log(err)
}
else {
console.log(data)
}
}):
});

Node : How to display value to an input only if there is a value

The add and update is happening on the same page, So initially all the input will be empty and when a data is click from the display page , all the data of the particular id should be displayed on all the inputs.
But when I'm trying to do that using ternary opeartor if condition , it doesn't seem to work.
EJS
<input
type="text"
class="form-control"
name="landingTitle"
value="<% result ? <%= result.landingTitle %> : '' %>" />
Backend
Node
// Initial Render
router.get("/", (req, res) => {
res.render("pages/dashboard");
});
//When the data is clicked for updation
router.get("/display/:id", (req, res) => {
MongoClient.connect(
process.env.ATLAS_URI,
{ useNewUrlParser: true },
(err, db) => {
if (err) throw err;
const dbo = db.db("xxx");
dbo
.collection("xxx")
.findOne({ _id: topic_id }, (err, result) => {
if (err) throw err;
res.render("pages/dashboard", {
result
});
db.close();
});
}
);
});
What am I doing wrong here ? Any advise will be appreciated , Thank you
I think you have a syntax issue here, please try the following and see if this works
value="<% if(result) { %> <%= result.landingTitle %> <% } else { %> '' <% } %>"
And if you are okay to use a non-inline version, you can always do the following
<%
var value = (result && result.landingTitle)? result.landingTitle : '';
%>
<input
type="text"
class="form-control"
name="landingTitle"
value="<%= value %>"
/>
There is one more simple and clean way. Check if result is defined using locals object inside the conditional operator.
<input
type="text"
class="form-control"
name="landingTitle"
value="<%= locals.result ? result.landingTitle : '' %>"
/>
It will work, whether you render the result object or not.

Trying to get data to display in a table

I'm working on my first node project using express and sequelize, and I'm not understanding how the page rendering works
I have the following function in my one of my models(sequelize):
getGreetings: function (req, res) {
Greeting.findAll({
}).then(function (data) {
console.log('Returned data for greetings: ' + data);
res.send({greetings:data});
})
}
Here is my route:
var Greeting = require('../models/greetings');
router.get('/', function(req, res) {
res.render('index', function(){
Greeting.getGreetings(req, res);
});
});
and my ejs table I want to display the data in:
<tbody>
<% for(var i=0; i < greetings.length; i++) { %>
<tr>
<td><%= greetings[i].name %></td>
<td><%= greetings[i].message %></td>
</tr>
<% } %>
</tbody>
This isn't displaying any of the html, but rather echoing out the json data. Can someone help explain why my html table isn't being populated?
but rather echoing out the json data.
This is because getGreetings() is always setting that as the response, by using res.send():
res.send({greetings:data});
To provide greetings to your view, you'll have to instead provide the data within the locals given to res.render():
res.render('index', { greetings: data });
The two methods don't cooperate with each other. Each is defined to end the response itself, so you'll only be able to use one per response.
If you revise getGreetings to return the promise created by .findAll():
getGreetings: function (req) {
return Greeting.findAll({
// ...
});
}
Then, the route handler can bind to it and decide how to make use of the result itself – whether it should use res.send() or res.render():
var Greeting = require('../models/greetings');
router.get('/', function(req, res) {
Greeting.getGreetings(req).then(function (greetings) {
res.render('index', { greetings: greetings });
});
});

Need help using EJS

I am exploring the use of the EJS templating system and am unsure of how to use it to get SQL data to be available to be rendered in a view.
In my app.js I have something like this:
conn.query("select name,age from people", function(err, people, moreResultSets) {
for (var i=0;i<people.length;i++){
console.log(people[i].NAME, "\t\t", people[i].AGE);
}
conn.close(function(){
console.log("Connection Closed");
});
});
And I have the following code to route the proper view:
app.get('/test1', function(req, res) {
res.render('pages/test1');
})
My confusion lies in making the people data available from the query
statement to be rendered in the view. All of the examples I have seen
have the variables defined locally inside the app.get code block and I
am unclear how to jump from that to my situation.
Thank you for any assistance you can provide!
-Andy
Render after you have the data.
app.get('/test1', function (req, res) {
conn.query("select name,age from people", function (err, people, moreResultSets) {
res.render('pages/test1', {
people: people
});
conn.close(function () {
console.log('Connection Closed');
});
});
});
HTML
<% if (people) { %>
<% for (var i = 0; i < people.length; i++) { %>
<div><%= people[i].name %></div>
<% } %>
<% } else { %>
<div>No people found</div>
<% } %>

Resources