Not able to compare Object Id using handlebars? - node.js

This is my first time using Handlebars. I am trying to compare user _id with logged in user id. I am saving data in MongoDB using mongoose. I found a helper from StackOverflow but it doesn't seem to compare value. The schema for user and Tracker and code I am using is below.
var trackerSchema = new mongoose.Schema({
description: {
type: String,
required: [true, 'Please add an description']
},
createdAt: {
type: Date,
default: Date.now
},
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
}
});
mongoose.model('Tracker', trackerSchema);
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
}
});
const User = mongoose.model('User', UserSchema);
Helper function in app.js file
const hbs = exphb.create({
extname: 'hbs',
defaultLayout: 'mainLayout',
layoutDir: __dirname + 'views/layouts/',
partialsDir: __dirname + '/views/partials/',
helpers: {
ifEqual: function (v1, v2, options) {
if (v1 != v2) {
return options.inverse(this);
}
return options.fn(this);
},
}
})
Using helper function ifEqual in handlebar file
{{#each list}}
<td>{{this.createdAt}}</td>
<td>{{this.user}}</td> //i am seeing this.user for example - **5ef9fb54f4bb8dff810104f7**
<td>
{{#ifEqual this.user looged_user_id }} //looged_user_id coming from req.user._id.toString()
Edit
<a href="/tracker/delete/{{this._id}}" onclick="return confirm('Are you sure to delete this record ?');"> Delete
</a>
{{else}}
Edit
<a href="#" onclick="return confirm('Are you sure to delete this record ?');"> Delete
</a>
{{/ifEqual}}
</td>
</tr>
{{/each}}
Please guide how can I compare two _ids.

You were missing two things:
Sending looged_user_id to your hbs:
res.render("tracker/list", { list: body, logged_user_id: req.user._id, });
Accessing logged_user_id it the right way inside the #each handlebar loop. When inside the loop you cannot directly use the data passed. You have to provide the right path to logged_user_id which in your case would be ../logged_user_id.
The ../ path segment references the parent template scope using which you can access logged_user_id.

In your code you need to pass your looged_user_id to template first, then only it will get in your helper function.
try this on http://tryhandlebarsjs.com/
Template:
{{#each list}}
<td>{{this.createdAt}}</td>
<td>{{this.user}}</td>
<td>
{{#ifCond this.user}} //Here 1 is just hardcoded insted of that need to change with actal variable
Edit for if
<a href="/tracker/delete/{{this._id}}" onclick="return confirm('Are you sure to delete this record ?');"> Delete looged_user_id
</a>
{{else}}
Edit for else
<a href="#" onclick="return confirm('Are you sure to delete this record ?');"> Delete
</a>
{{/ifCond}}
</td>
</tr>
{{/each}}
Context:
{
"list": [{
"user": 1,
"content": "hello"
},{
"user": 2,
"content": "world"
}],
}
Register Helper function:
Handlebars.registerHelper('ifCond', function(v1, options) {
if(v1 === looged_user_id ) {
return options.fn(this);
}
return options.inverse(this);
});
Result:
<td></td>
<td>1</td>
<td>
Edit for if
<a href="/tracker/delete/" onclick="return confirm('Are you sure to delete this record ?');"> Delete looged_user_id
</a>
</td>
</tr>
<td></td>
<td>2</td>
<td>
Edit for else
<a href="#" onclick="return confirm('Are you sure to delete this record ?');"> Delete
</a>
</td>
</tr>

Related

handlebars.js build in helper #each not working

I am using expressjs and mongoose in backend and handlebars as view engine.
Here is my method in index js
const router = require('express').Router()
const Product = require('../../models/Products')
// Products
router.get('/products',async (req, res) => {
try{
const products = await Product.find()
res.status(200).render('products',{products})
}catch(err){
res.status(400).render('products')
}
})
Documents inside product collection is like this:
[
{
_id: new ObjectId("632d74a0b828b58a1d25b047"),
title: 'Footballs',
description: 'This is a nice product.',
images: [
'/product-images/1663923360491/image1.png',
'/product-images/1663923360491/image2.png'
],
categories: [ 'football', 'balls', 'sports' ],
price: 800,
stock: 300,
createdAt: 2022-09-23T08:56:00.546Z,
updatedAt: 2022-09-23T08:56:00.546Z,
__v: 0
}
]
And here is the foreach sentence at index.hbs
<table>
<thead>
<tr>
<td>Date</td>
<td>Product</td>
<td>Price</td>
<td>Options</td>
</tr>
</thead>
<tbody>
{{#each products}}
<tr>
<td>{{this.createdAt}}</td>
<td>{{this.title}}</td>
<td>₹{{this.price}}</td>
<td>
<button>edit</button>
<button>delete</button>
</td>
</tr>
{{/each}}
</tbody>
</table>
This code is not working (td tag is empty). But when I put {{#index}},the index of the current array item is displaying but other values are not displaying.
{{#each products}}
<tr>
<td>{{#index}}</td>
<td>{{this.title}}</td>
<td>₹{{this.price}}</td>
<td>
<button>edit</button>
<button>delete</button>
</td>
</tr>
{{/each}}
Any help is greatly appreciated, thanks in advance!
You don't need to use this here:
{{#each products}}
<tr>
<td>{{createdAt}}</td>
<td>{{title}}</td>
<td>₹{{price}}</td>
<td>
<button>edit</button>
<button>delete</button>
</td>
</tr>
{{/each}}
If using mongoose, this issue can be solved by using .lean() to get a json object (instead of a mongoose one):
const products = await Product.find().lean()
res.status(200).render('products',{products})

Collections query with find method and render to ejs

I have operator Collection in mongoDB. And I want to get all information in ejs table so I wrote below codes. But I get error with operators.forEach is not a functions How can I solve this problem ?
This is Collection model:
const operatorSchema = new Schema({
operatorName: {
type: String
},
productsSerialNumber:[{productSerialNumbers: String}],
operatorSerialNumber: {
type: Number
},
users:[{
email:String,
payment:Number,
paymentsData: Date,
}],
operatorState:{
type: Boolean,
}
});
And this is the query function:
exports.getOperatorInformations = (req, res, next)=>{
Operators.find({},function(err,docs){
docs.forEach(function(dataCatch){
console.log(dataCatch.users)
res.render('home',{operators: dataCatch});
})
})
}
}
And ejs file part:
<% operators.forEach(function(data){ %>
<tr>
<td>
<%= data.operatorName %>
</td>
<td>
<%= data.productsSerialNumber %>
</td>
<td>
<%= data.productsSerialNumber %>
</td>
<% })%>
<% data.users.forEach(function(data){ %>
<td>
<%= data.users.email %>
</td>
<td>
<%= data.users.paymentsData %>
</td>
<td>
<!-- <%= data.users.payment %> -->
</td>
</tr>
<% })%>
</tr>

ExpressJS : SQLITE_RANGE: column index out of range WHERE condition

I am working on a project using express , EJS and SQLite , So i made a function that select data from the database, and render it to the interface, this is the function:
function findHomeforSell(req , res , next){
const sell = "Sell";
db.all('SELECT * FROM home WHERE for = ? ', [
sell
] ,function(err , rows){
if (err) { return next(err);}
var homes = rows.map(function(row) {
return {
id: row.id,
location: row.Location,
four: row.for,
space: row.space,
bathrooms: row.bathrooms,
bedrooms: row.bedrooms,
price: row.price,
url: '/' + row.id
}
});
res.locals.homes = homes;
});
};
the ejs file:
<div class="house-list" id="buy">
<h1>Buy</h1>
<ul class="todo-list">
<% homes.forEach(function(home) { %>
<li>
<form action="<%= home.url %>" method="post">
<div class="view">
<table>
<thead>
<th>Location</th>
<th>For</th>
<th>Space</th>
<th>Bathroom</th>
<th>Bedroom</th>
<th>Price</th>
</thead>
<tbody>
<td><label ondblclick=""><%= home.location %> </label></td>
<td><label ondblclick=""> <%= home.four %></label></td>
<td><label ondblclick=""><%= home.space %> SQRM </label></td>
<td><label ondblclick=""> <%= home.bathrooms %></label></td>
<td><label ondblclick=""><%= home.bedrooms %> </label></td>
<td><label ondblclick="">$ <%= home.price %> SDG</label></td>
</tbody>
</table>
</div>
</li>
<% }); %>
</ul>
</div>
and the error:
SQLITE_RANGE: column index out of range
I couldn't understand the error so what to do

I can't change the value in the database - array

I need to update the comment status, i.e. the name of the "approve" field. To this end, I created the AJAX script also the backend seems correct because it receives a message after clicking the button. I don't know why I can't save the "approve" value to the database. Please help. I use NodeJS, MongoDB, Express, and EJS for frontend.
My database:
My frontend:
<% post.comments.forEach(function (comment) { %>
<tr>
<td> <%= comment._id %> </td>
<td> <%= comment.username %> </td>
<td> <%= comment.comment %> </td>
<form method="post" onsubmit="return doApprove(this);">
<input type="hidden" name="post_id" value="<%= post._id %>" />
<input type="hidden" id="comment_id" name="comment_id">
<td> <input class="approve-comment" type="checkbox" name="approve" value="true">
<button class="btn btn-info" value="Approve"/>
</td>
</form>
<% }) %>
</tr>
</table>
</div>
<script>
function doApprove(form) {
var formData= {approve:form.approve.value};
$.ajax({
url: "/do-edit-comment",
method: "POST",
data: formData,
success: function (response) {
formData._id =response._id;
alert(response.text);
}
});
return false;
}
</script>
My backend:
app.post("/do-edit-comment", function (req,res) {
blog.collection("posts").updateOne({
"_id": ObjectId(req.body.id),
"comments._id": ObjectId(req.body.id)
},{
$set: {
"comments": {approve: req.body.approve}
}
}, function (error,document) {
res.send({
text: "comment approved"
});
});
});
To update a single element from an array, what you need is the $[<identifer>] array update operator. For the scenario described in your question, the update query in the server should be something like this:
blog.collection("posts").updateOne(
{ "_id": ObjectId(req.body.post_id), },
{ $set: { "comments.$[comment].approve": req.body.approve } },
{ arrayFilters: [{ "comment._id": ObjectId(req.body.commentId) }] },
function (error, document) {
res.send({
text: "comment approved"
});
}
)
EDIT(Front-end issues/fix)
So I figured there are some issues with the front end code too. This edit attempts to explain/fix those issues.
Issues:
1. The backend expects a commentId in the request object(req.body.commentId) to be able to identify the comment to update but you are not sending that from the front end.
2. The backend needs the id of the post to uniquely identify the post to update, but you are not sending that from the front end.
3. The approve value in the form data sent from the front-end is a string and it would always be "true". This is not what you want, you want to send a boolean value(true or false) depending on if the checkbox is checked or not.
Fix:
Update the form template to this:
<form method="post" onsubmit="return doApprove(event);">
<input type="hidden" name="post_id" value="<%= post._id %>" />
<input type="hidden" id="<%= comment._id %>" name="comment_id" />
<td> <input class="approve-comment" type="checkbox" name="approve" value="true">
<button class="btn btn-info" value="Approve"/>
</td>
</form>
Changes:
- The doApprove handler attached to the submit event of the form is now called with event instead of this.
- I updated the value of the id attribute for the input#name="comment_id" element to the actual comment._id value.
And in the script tag, update the doApprove function to this:
function doApprove(event) {
event.preventDefault();
const form = event.target;
var formData = {
approve: form.approve.checked, // form.approve.checked would be true if the checkbox is checked and false if it isn't
post_id: form.post_id.value, // The value of the input#name=post_id element
commentId: form.comment_id.id, // The id attribute of the input#name=comment_id element
};
$.ajax({
url: "/do-edit-comment",
method: "POST",
data: formData,
success: function (response) {
formData._id =response._id;
alert(response.text);
}
});
return false;
}
I hope that helps.

Nodejs - MongoDB Query

I have a little problem with my Thesis project.
I have a mongodb database with abour 400k entries styled like this:(i've translated the variables so if theres any typo, sorry);
var mongoose = require("mongoose");
var work_schema = new mongoose.Schema({
worktype: String,
ordernumber: String,
art_code: String,
qta: String,
number_of_operatos: String,
1_op_code: String,
2_op_code: String,
3_op_code: String,
4_op_code: String,
phase: String,
notes: String,
continued: String, //just a flag
date_start: String, // DD-MM-YYYY
date_end: String, // DD-MM-YYYY
time_start: String, //HH:MM:SS
time_end: String, //HH:MM:SS
datainiziopart: String, //this is the date parsed like this YYYYMMDD i needed it for another purpose
datafinepart: String, //this is the date parsed like this YYYYMMDD i needed it for another purpose
cronsec: String,
cronsec1: String,
cronsec2: String,
cronsec3: String,
cronsec4: String,
cronsec5: String,
cronsec6: String,
cronsec7: String,
operationtimesec: String,
designtimesec: String,
totalecausalisec: String,
ke: String,
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String,
codicereparto: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "Reparti"
},
nomereparto: String,
descrizionereparto: String
}
}
});
module.exports = mongoose.model("Work", work_schema);
As you can see the schema is not small at all, and having more than 400k entries, i need to query them when exporting/showing.
I used the limit function to show the latest entries.
I want to create a Page with a datepicker to query the data, or using the
date_start: String, // DD-MM-YYYY
or using the
datainiziopart // YYYYMMDD like <>=
Can you help me write the nodejs code to render a page with the result?
I use express if that can help.
i tried to do this
router.get("/risultati", function(req, res) {
Request.getAllRequestListingsCb(function (err, docs){
res.render('pannello/risultati', { rL: docs });
});
});
router.post("/ricercautente", function(req, res) {
var data = req.body.filtro;
var datadivisa = data.split(' - ');
var datestart= moment(datadivisa[0], 'DD-MM-YYYY').format('DD-MM-YYYY');
var dateend= moment(datadivisa[1], 'DD-MM-YYYY').format('DD-MM-YYYY');
//res.redirect("/pannello/utentetutti");
module.exports.getAllRequestListings = function (callback) {
var query = {"datainizio": {"$gte": new Date(datainizio), "$lt": new Date(datafine)}};
Lavori.find(query, callback);
};
res.redirect('pannello/risultati');
});
<div class="" align=center>
<form action="/ricercautente" method="post">
<input type="text" name="filtro" id="filtro" />
<button class="pure-button pure-button-warning" name="" id="" type="submit">Submit</button>
</form>
</div
and on another page
<tbody>
<% lavoritrovati.forEach(function(lavoro){ %>
<tr>
<td> <%=lavoro.author.codicereparto.nomereparto%> </td>
<td> <%=lavoro.tipodilavoro%> </td>
<td> <%=lavoro.ordineproduzione %> </td>
<td> <%=lavoro.codicearticolo %> </td>
<td> <%=lavoro.quantita %> </td>
<td> <%=lavoro.noperatori %> </td>
<td> <%=lavoro.codoperatori%> </td>
<td> <%=lavoro.codoperatori2%> </td>
<td> <%=lavoro.codoperatori3%> </td>
<td> <%=lavoro.codoperatori4%> </td>
<td> <%=lavoro.fase %> </td>
<td> <%=lavoro.note %> </td>
<td> <%=lavoro.datainizio %> </td>
<td> <%=lavoro.timestart %> </td>
<td> <%=lavoro.datafine %> </td>
<td> <%=lavoro.timeend %> </td>
<td> <%=lavoro.continuato %> </td>
<td> <%=lavoro.cronsec %> </td>
<td> <%=lavoro.cronsec1 %> </td>
<td> <%=lavoro.cronsec2 %> </td>
<td> <%=lavoro.cronsec3 %> </td>
<td> <%=lavoro.cronsec4 %> </td>
<td> <%=lavoro.cronsec5 %> </td>
<td> <%=lavoro.cronsec6 %> </td>
<td> <%=lavoro.cronsec7 %> </td>
<td> <%=lavoro.designtimesec %> </td>
<td> <%=lavoro.operationtimesec %> </td>
<td> <%=lavoro.ke %> </td>
<% }); %>

Resources