handlebars.js build in helper #each not working - node.js

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})

Related

How do I tailor my query to get a specific title?

I have a query in my app.js file that renders into my list page list.ejs found at http://localhost:4100/list. As the name may suggest, the list page displays a list of ALL the transactions stored in the database, though I would be more interested in only displaying all the transactions strictly within the county of Nairobi.
Find below the contents of my app.js file:
app.get('/list', (req,res)=> {
let countyName;
countyName = transModel.findOne({ transCounty : /Nairobi/i, })
.limit(5)
.select({ transCounty:1})
.exec( (err, result)=> {
if (err) throw err;
console.log('>> ' +result);
return result;
});
console.log ('countyName: ' +countyName);
transModel.find( (err, docs)=> {
if (!err)
{
res.render('list', {data : docs, countyName: countyName});
}
else
{
// res.status(status).send(body);
}
})
});
In the terminal, the code above yeilds:
countyName: undefined
>> { _id: 609f7ed8fe1fd8b3193b0b77, transCounty: 'Nairobi' }
My list.ejs looks like this:
<h1> Transactions </h1>
<p>
Name of County: <%= countyName %>
</p>
<table>
<tr>
<th> _id </th>
<th> Transaction Amount </th>
<th> Transaction County </th>
<th> Transaction Industry </th>
</tr>
<% data.forEach(function(entry) {%>
<tr>
<td> <%=entry._id%> </td>
<td> <%=entry.transAmount%> </td>
<td> <%=entry.transCounty%> </td>
<td> <%=entry.transIndustry%> </td>
</tr>
<%});%>
</table>
The above list.ejs file, though correctly renders a table with the desired content from the database isn't able to pick the name of the County. Kindly help me figure out how I can achieve this.
Find below an image of the rendered list.ejs:
Kindly note Name of county is undefined.
How do I formulate my query be able to yield all transactions within only Nairobi, and also display the name of the county in the ejs file.
Looking forward to your help.
You should wait for the promise to resolve before using its value:
countyName = await transModel.findOne({
transCounty: /Nairobi/i,
})
.limit(5)
.select({
transCounty: 1
})
.exec();

Uncaught IntegrationError: Invalid stripe.redirectToCheckout parameter: items.0.price is not an accepted parameter

My goal is to use react front end to setup a stripe checkout using node. I mapped the apiId using the key prop to iterate over all the items in my list. But there is an integration warning inside the console and I'm not sure why. I've added the js.stripe script src into my html file so I don't understand why an API call is not being made.
function checkout() {
stripe.redirectToCheckout({
items: items.map(item => ({
quantity: item.quantity,
price: item.apiId
})),
successUrl: "https://www.website.com/success",
cancelUrl: "https://www.website.com/canceled",
})
}
return (
<div>
<table>
<thead>
<tr>
<th>Name</th>
<th>Image</th>
<th>Quanity</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{items.map((item) => (
<tr key={item.apiId}>
<td>{item.name}</td>
<td>
<img
src={`/images/${item.apiId}.jpg`}
alt={item.name}
width={180}
/>
</td>
<td>{item.quantity}</td>
<td>{formatPrice(item.price)}</td>
</tr>
))}
<tr>
<td style={{ textAlign: "right" }} colSpan={3}>
Total:
</td>
<td>{formatPrice(totalPrice(items))}</td>
</tr>
<tr>
<td style={{ textAlign: "right" }} colSpan={4}>
<button onClick={checkout}>Complete checkout</button>
</td>
</tr>
</tbody>
</table>
</div>
)
}
The items field only accepts an array of SKU/Plans and a quantity. If you're using Prices you want to use lineItems: https://stripe.com/docs/js/checkout/redirect_to_checkout#stripe_checkout_redirect_to_checkout-options-lineItems

How can i render data on change?

I'm trying to build a project in nodejs as server and firebase as my realtime db and having some problems with forwarding the data to my html.
I getting the error:
Cannot set headers after they are sent to the client
on change
I'm trying to pass the updated arr to html but can't find a way to do that.
server.js:
const locksRef = await firebase.firebase.database().ref('locks')
let arr = []
//get list of locks
const t = locksRef.on('value', (data) => {
tempResult3 = data.val()
result3 = []
const numOfKeys = Object.keys(tempResult3)
numOfKeys.forEach((x) => {
result3.push(tempResult3[x])
})
result3.forEach((k) => {
myLocks.forEach((my) => {
if (k.id == my) {
arr.push(k)
}
})
})
res.render('ListOfLocks', { arr })
})
html
<body>
<h1>ListOfHouses</h1>
<table border="1px solid black">
<thead>
<th>Name And Address</th>
</thead>
<tbody>
{{#each arr}}
<tr>
<td id="data"> {{name}} - {{address}}</td>
<td>
<form action="/seekKeys" method="post"><button name="{{locks}}" type="submit">LookForKey</button>
</form>
</td>
</tr>
{{/each}}
</tbody>
</table>
</body>

Meteor Blaze iterate over dynamically created object

I'm trying to iterate with Blaze over dynamically created object. I have the collection and the object, but I can't display the data in my tables and I don't understand why.
Here's my code to retrieve the object :
In my Template Helpers :
fields: ()=> {
var collectionSelected = FlowRouter.current().params.collectionName;
// var data = Mongo.Collection.get(collectionSelected).find().count();
var collectionObject = Collections.findOne({name: collectionSelected});
console.log(Collections.findOne({name: collectionSelected}));
return Collections.findOne({name: collectionSelected});
},
values: ()=> {
var collectionSelected = FlowRouter.getParam('collectionName');
var collectionObject = Collections.findOne({name: collectionSelected});
var dataArray = [];
var data = Meteor.call('findElmt', collectionSelected, function(err, res){
console.log('VALUES : ');
console.log(res);
return res;
});
},
The findElmt method :
findElmt(collectionName){
if (global.hasOwnProperty(collectionName)){
var res = Mongo.Collection.get(collectionName).find().fetch();
console.log(res);
return res;
}
else {
global[collectionName] = new Meteor.Collection(collectionName);
var res = Mongo.Collection.get(collectionName).find().fetch();
console.log(res);
return res;
}
}
And finally the way I'm trying to display it with Blaze :
<table data-toggle="table" data-show-columns="true" data-search="true" data-pagination="true">
{{#with fields}}
{{#if Template.subscriptionsReady}}
<thead>
<tr>
{{#each fields.fieldsName}}
<th data-sortable="true">{{this}}</th>
{{/each}}
</tr>
</thead>
{{else}}
<p>Loading...</p>
{{/if}}
{{/with}}
<tbody>
{{#each values}}
<tr>
{{#each valueString in values.items}}
<td>{{valueString}}</td>
{{/each}}
</tr>
{{/each}}
</tbody>
</table>
If you have any advice on what I'm doing wrong, thank you !
EDIT 1 : I added the fields helper !
Supposing that values is an array of JsonObject with the field items, you are iterating the wrong way.
When using {{#each}} and not {{#each in}} you can access directly your properties with itemsor with this.items.
If values is an array of JsonObject :
<tbody>
{{#each values}}
<tr>
{{#each valueString in this.items}} // values.items -> this.items
<td>{{valueString}}</td>
{{/each}}
</tr>
{{/each}}
</tbody>
If values is a JsonObject, you can use with :
<tbody>
{{#with values}}
<tr>
{{#each valueString in this.items}} // values.items -> this.items
<td>{{valueString}}</td>
{{/each}}
</tr>
{{/with}}
</tbody>
Then to have a reactive returned value with Method call you can use the following package :
https://atmospherejs.com/simple/reactive-method
Thank you a lot for your help, I finally nailed it.
Here's the final code for the future lost soul like me !
Template Helpers :
fields: ()=> {
var collectionSelected = FlowRouter.current().params.collectionName;
// var data = Mongo.Collection.get(collectionSelected).find().count();
var collectionObject = Collections.findOne({name: collectionSelected});
console.log(Collections.findOne({name: collectionSelected}));
return Collections.findOne({name: collectionSelected});
},
values: ()=> {
var collectionSelected = FlowRouter.getParam('collectionName');
var collectionObject = Collections.findOne({name: collectionSelected});
var dataArray = [];
console.log(ReactiveMethod.call("findElmt", collectionSelected));
return ReactiveMethod.call("findElmt", collectionSelected);
}
The server side FindElmt method didn't change,
and finally the Blaze code :
<table data-toggle="table" data-show-columns="true" data-search="true" data-pagination="true">
{{#with fields}}
{{#if Template.subscriptionsReady}}
<thead>
<tr>
{{#each fields.fieldsName}}
<th data-sortable="true">{{this}}</th>
{{else}}
{{! will this fix this issue? }}
{{/each}}
</tr>
</thead>
{{else}}
<p>Loading...</p>
{{/if}}
{{else}}
{{! will this fix this issue? }}
{{/with}}
{{#with values}}
<tbody>
{{#each values}}
<tr>
{{#each valueString in this.items}}
<td>{{valueString}}</td>
{{else}}
{{! will this fix this issue? }}
{{/each}}
</tr>
{{else}}
{{! will this fix this issue? }}
{{/each}}
</tbody>
{{else}}
{{! will this fix this issue? }}
{{/with}}
</table>

How to display specific data in ejs from mongoose?

I am new to NodeJS and MongoDB .I want to specific data from my database using mongoose . Those specific data are decided by a searchIndex and searchValue which is provided as a post request
The ejs page which provides the searchIndex and searchValue
<form action="/searchDetails" method="post">
<table>
<tr>
<td>
Select Search Category:
</td>
<td>
<select name="searchIndex">
<option>Name</option>
<option>Rollno</option>
<option>Branch</option>
<option>Hostel</option>
<option>RoomNo</option>
<option>ContactNo</option>
<option>Semester</option>
<option>FName</option>
<option>MName</option>
<option>Address</option>
</select>
</td>
</tr>
<tr>
<td>Enter the Search Value:</td>
<td><input type="text" name="searchValue"></td>
</tr>
<tr>
<td><input type="Submit" name="Search"></td>
</tr>
</table>
</form>
This is my mongoose schema
var mongoose = require('mongoose');
var userSchema = new mongoose.Schema({
username: String,
password: String,
});
var studentSchema=new mongoose.Schema({
Name:String,
Rollno:String,
Branch:String,
Hostel:String,
RoomNo:String,
ContactNo:String,
Semester:String,
FName :String,
MName:String,
Address:String,
});
mongoose.model('Students3', studentSchema);
mongoose.model('User', userSchema);
this is my server.js
router.post('/searchDetails', function(req, res, next) {
var searchIndex=req.body.searchIndex;
var searchValue=req.body.searchValue;
students.find({searchIndex:searchValue},function(err,data){
if(err)
{
console.log(err);
}
else if(!data)
{
console.log('no data');
res.redirect('/homepage');
}
else
{
console.log(data);
output=data;
res.redirect('/editStudents')
router.get('/editStudents',function(req,res,next){
res.render('editStudents',{output});
});
}
});
});
this is my ejs where i display the value
<table border="1">
<tr>
<td>
<i>Name</i>
</td>
<td>
<i>Rollno</i>
</td>
<td>
<i>Branch</i>
</td>
<td>
<i>Hostel</i>
</td>
<td>
<i>RoomNo</i>
</td>
<td>
<i>ContactNo</i>
</td>
<td>
<i>Semester</i>
</td>
<td>
<i>Father's Name</i>
</td><td>
<i>Mother's Name</i>
</td><td>
<i>Address</i>
</td>
</tr>
<%
output.forEach(function(name)
{
%>
<tr>
<td><%=name.Name%></td>
<td><%=name.Rollno%></td>
<td><%=name.Branch%></td>
<td><%=name.Hostel%></td>
<td><%=name.RoomNo%></td>
<td><%=name.ContactNo%></td>
<td><%=name.Semester%></td>
<td><%=name.FName%></td>
<td><%=name.MName%></td>
<td><%=name.Address%></td>
</tr>
<%
})
%>
</table>
But the problem is it doesnot display any data.please help

Resources