Handlebars won't show one out of 6 values - javascript

So I'm linking in some values to an .hbs-file and most of the values is returned. But for some reason, one of the values is not returning anything. The .hbs:
<nav>
<h2>Working Files</h2>
{{#if snippets }}
<ul>
{{#each snippets}}
<li class={{ this.active }}>{{ this.fileType }}</span>
</li>
{{/each}}
</ul>
{{/if}}
</nav>
And I'm sending them in like this:
router.route("/home/:id")
.get(restrict, function(req, res) {
User.findOne({ user: req.session.Auth.username }, function(error, data) {
Snippet.find({ postedBy: data._id}).exec()
.then(function(data) {
Snippet.find({ _id: req.params.id}).exec()
.then((snippetID) => {
// This is what I send it -------------------------------------------------
let context = {
snippets: data.map(function(snippet) { // Gets the snippet info for nav
return {
name: snippet.title,
fileType: snippet.fileName,
id: "/home/" + snippet._id
};
}),
text: snippetID[0].snippet[0].text, // Gets the snippet-text, and writes it
sessionId: snippetID[0]._id, // For the CRUD to get the id
active: "active"
};
res.render("../views/home", context);
// ------------------------------------
}).catch((err) => {console.log(err)})
}). catch(function(err) {console.log(err)});
});
});
It's the "this.active" that holds no value at all. I've been scratching my head over and over about this, and I can't understand why that value won't follow. All the other values do follow. I've even tried to set the "active"-key to the same value as "id" or "text", but no luck.
Do anyone know what the problem is?

Related

Displaying binary data in a HBS view from MongoDB - Node js

I have a hbs view which is receiving and displaying some data that I am pulling from MongoDB.
It is displaying all my data correctly except for the binary data which I am using inside of an img element. If I copy the binary data from the MongoDB document and put it in the img element it displays in the browser. For this reason I feel that the variable I am referencing is incorrect?
I have also tried to use 'img.$binary' and that does not show any data at all.
This would seem to me the way to do it though with 'img' being an object?
But when I log 'img' to the console it seems to be the right one. When I log 'img.$binary' it is undefined. I am definitely getting some data in the img tag as it shows this when I run node js (with 'img' in the appropriate place in hbs view):
HTML:
My route:
router.get('/', async (req, res) => {
const products = await Product.find()
res.render('shop', {
title: 'Shop',
products: products
})
})
Mongoose Model:
const ProductSchema = new mongoose.Schema(
{
title: { type: String, required: true, unique: true },
desc: { type: String, required: true },
img: { type: Buffer },
categories: { type: Array },
size: { type: String },
colour: { type: String },
price: { type: Number, required: true },
},
{ timestamps: true }
)
MongoDB Collection:
{
"_id" : ObjectId("62dd1127884e20dcfbb09a6c"),
"title" : "'Northface tshirt'",
"desc" : "'test'",
"img" : { "$binary" : "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6CAIAAAAH...(shortened for viewability), "$type" : "00" },
"categories" : [],
"size" : "'XL'",
"colour" : "'White'",
"price" : 80,
"createdAt" : ISODate("2022-07-24T09:30:15.974Z"),
"updatedAt" : ISODate("2022-07-24T09:30:15.974Z"),
"__v" : 0
}
HBS view:
<body>
<div class="grid-wrapper">
{{!-- Object --}}
{{#each products}}
<div class="grid-number">
<img src="data:image/jpg;base64,{{img}}">
{{!-- String --}}
<h2>{{title}}</h2>
{{!-- Array --}}
{{#each categories}}
{{!-- Strings --}}
<p>Apparel Type: {{apparelType}}</p>
<p>Gender: {{gender}}</p>
{{/each}}
<p>Size: {{size}}</p>
<p>Price: {{price}}</p>
<p>Colour: {{colour}}</p>
</div>
{{/each}}
</div>
Any help would be greatly appreciated, I have searched for a couple hours now and seen some similar issues but nothing has helped so far. Hoping someone with more experience with data will know what is going wrong here. Thanks in advance.
Not exactly an answer for inserting the binary data straight into the img tag but I have now found a way to display the DB document images dynamically.
Firstly, I added a route to view the img for each document in the collection by it's id:
//VIEW PRODUCT IMG
router.get('/:id/img', async (req, res) => {
try {
const product = await Product.findById(req.params.id)
if (!product || !product.img) {
throw new Error()
}
res.set('Content-Type', 'image/jpg')
res.send(product.img)
} catch (e) {
res.status(404).send()
}
})
Then, modified my img src attribute to point towards the route + inserted the id's of the documents dynamically in the hbs template:
<div class="grid-wrapper">
{{!-- Object --}}
{{#each products}}
<div class="grid-number">
<img src="products/{{id}}</img">
{{!-- String --}}
<h2>{{title}}</h2>
{{!-- Array --}}
{{#each categories}}
{{!-- Strings --}}
<p>Apparel Type: {{apparelType}}</p>
<p>Gender: {{gender}}</p>
{{/each}}
<p>Size: {{size}}</p>
<p>Price: {{price}}</p>
<p>Colour: {{colour}}</p>
</div>
{{/each}}
</div>
I can now display the images as intended:

Get Specific Object from Array in MongoDB collection into handlebars table

I'm trying to build a table with values from an Array of objects from mongodb, but I only can get every value and only need the specific value.
So I made a query like this
router.get("/arquiveExpense", ensureAuthenticated, (req, res) => {
House.find({
userID: req.user.id,
expensesHouse: { $elemMatch: { status: "Private" } }
}).then(house => {
console.log(house);
res.render("houses/arquiveExpense", {
house: house
});
});
});
I want to retrieve the specific value from expensesHouse with status 'Private'.
And in handlebars I have this structure
<tbody>
<tr>
{{#each house}}
<td>{{expenseType}}</td>
<td>{{price}}€</td>
<td>{{payAt}}</td>
<td>{{formatDate date 'MMMM Do YYYY'}}</td>
<td>
<a href="/houses/showExpense/{{id}}" id="detailsExpense"
class="btn btn-outline-light mb-3"><i class="fas fa-eye mr-2"></i>Details
</a>
<td>
<a href="/houses/editExpense/{{id}}" id="editExpense" class="btn btn-outline-light mb-3"><i
class="fas fa-edit mr-2"></i>Edit
</td>
</tr>
{{else}}
<p>No expenses</p>
{{/each}}
</tbody>
And after this handlebars, this is the result
The Schema structure is the follow
So I want to show in the web page the value from expensesHouse with the Status 'Private'.
How can I change my code to retrieve only this value ?
Please update your code with the below, it resolves your issues with code & also with query :
router.get("/arquiveExpense", ensureAuthenticated, async (req, res) => {
try {
let house = await House.findOne({ // You can use findOne as if userID is unique
userID: req.user.id
}, { expensesHouse: { $elemMatch: { status: "Private" } } }) //$elemMatch in projection helps you to get what is needed
if (house) { // .findOne() returns null if no document found, else an object
console.log(house);
res.render("houses/arquiveExpense", {
house: house
});
} else { // No document found
console.log('No house found')
}
} catch (error) {
console.log('Error at DB call ::', error)
}
})

vue js not displaying nested json

My vue.js code is unable to access a reference in a returned json object.
The vue.js code
new Vue({
el: '#axios',
data: function() {
return {
bikes: null,
baseurl: "https://" + document.querySelector('#axios').dataset.hostportname + "/",
}
},
mounted () {
axios({
method: 'get',
url: 'api/v1/bicycles',
baseURL: this.baseurl
})
.then(response => {
this.bikes = response.data
console.log("now bikes are " + JSON.stringify(this.bikes[0].owner.userName));
})
.catch(error => console.log("There is an error getting bikes: " + error))
}
})
If the HTML file (just a part) is
<div id="axios" th:data-hostportname="${hostportname}">
<li v-for="bike in bikes" :key="bike.id">
{{ bike.make }} ------- {{ bike.owner }}
</li>
</div>
Then the html output is
dawes -------- { "id": 1, "userName": "user1"}
whyte -------- { "id": 2, "userName": "user2"}
whyte -------- { "id": 3, "userName": "user3"}
And the console.log output is
now bikes are "user1"
if I try to output the owner id alone
<div id="axios" th:data-hostportname="${hostportname}">
<li v-for="bike in bikes" :key="bike.id">
{{ bike.make }} ------ {{ bike.owner.id }}
</li>
</div>
no output with a console error of
TypeError: "bike.owner is undefined"
So the Axios code is returning the correct data. Each object in the array is accessible. But the nested object within each array member is not accessible at a field level.
Just to make clear, if I ask for {{ bike.owner }} then I get a displayed the oener record that is referenced by the bike record. If I ask for {{ bile.owner.id }} then I get the console.log error of bike.owner is undefined and nothing is displayed. So I don't see how this is a loading problem unless bike.owner.id takes longer to retrieve than bike.owner, even though the latter displays.
Can someone explain what I am misunderstanding?
Regards.
So I found the root cause and it had nothing to do with vue.
Basically I have two models - owners and bicycles. Bicycles have a ref to a single owner. And owners have ref to an array of bicycles. I added #JsonIdentityInfo to both. And that was my problem.
Changing this to having #JsonIdentityInfo only in owner then allowed it to work.
Many thanks for all of the suggestions.
I think the response you are getting is as follows where owner is also a string.
So you might have to parse it before assigning it to bikes.
[{
make: 'one',
owner: '{ "id": 1, "userName": "user1"}'
}, {
make: 'two',
owner: '{ "id": 2, "userName": "user2"}'
}, {
make: 'three',
owner: '{ "id": 3, "userName": "user2"}'
}]
Hope this helps.
Update 1
Can you try adding a loading flag?
https://v2.vuejs.org/v2/cookbook/using-axios-to-consume-apis.html
new Vue({
el: '#axios',
data: function() {
return {
bikes: null,
loading: true
baseurl: "https://" + document.querySelector('#axios').dataset.hostportname + "/",
}
},
mounted () {
axios({
method: 'get',
url: 'api/v1/bicycles',
baseURL: this.baseurl
})
.then(response => {
this.bikes = response.data
console.log("now bikes are " + JSON.stringify(this.bikes[0].owner.userName));
})
.catch(error => console.log("There is an error getting bikes: " + error)).finally(() => this.loading = false)
}
})
And add v-if to your block
<div id="axios" v-if="!loading" th:data-hostportname="${hostportname}">
<li v-for="bike in bikes" :key="bike.id">
{{ bike.make }} ------ {{ bike.owner.id }}
</li>
</div>

Show json result with vue.js

Hi i am try to show json file result with vue.js the target is that result will be showed on value.
this is my code:
data () {
return {
fetchData: function () {
var self = this;
self .$http.get( "/api/casetotalactivation", function( data ) {
self.items = data;
});
},
statsCards: [
{
type: 'warning',
icon: 'ti-server',
title: 'Cases',
value: this.items,
footerText: 'Updated now',
footerIcon: 'ti-reload'
}
],
use this code:
<div id="vueapp">
<textarea v-model="jsonstr" rows="8" cols="40"></textarea>
<pre>{{ jsonstr | pretty }}</pre>
</div>
and JS:
new Vue({
el: '#vueapp',
data: {
jsonstr: '{"id":1,"name":"A green door","price":12.50,"tags":["home","green"]}'
},
filters: {
pretty: function(value) {
return JSON.stringify(JSON.parse(value), null, 2);
}
}
})
HTML and JS have this built into the language. Try...
<pre>{{ yourObject }}</pre>
This gives the default indent, to specify a custom indent provide it as the third argument to JSON.stringify(...).
// replace 2 with '\t' to do tab indentation
<pre>{{ JSON.stringify(yourObject, null, 2) }}</pre>
If you're outside of Vue then using some combo of the above snipped will do.
just use <pre>
<pre>{{json}}</pre>
The following code shows how to show json result with Vue 3
Display a stringified json object inside a <textarea> using v-model
Display object properties with <li v-for="">
<template>
<div class="hello">
<textarea v-model="listDataString" rows="20" cols="80"></textarea>
<ul id="items">
<li v-for="(item, index) in listData" :key="index">
{{ `${item.text} [${item.id}]` }}
</li>
</ul>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "RenderList",
props: {
msg: String,
},
data() {
return {
listDataString: String,
listData: [], // placeholder
};
},
mounted() {
axios
.get("=== [API_ENDPOINT] ===")
.then((response) => {
this.listDataString = JSON.stringify(response.data, null, "\t");
this.listData = response.data;
console.log(this.listDataString);
return response; // multiline arrow function must return
});
},
};
</script>
If the /api is only on the dev server you can create a vue.config.js file in the app root folder.
module.exports = {
devServer: {
before: function(app, server) {
app.get('/api', function(req, res) {
const result = [{
type: 'warning',
icon: 'ti-server',
title: 'Cases',
value: this.items,
footerText: 'Updated now',
footerIcon: 'ti-reload'}];
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(result));
});
}
}
}
With this files when I run npm run serve, I get the json object when navigating to /api and my regular app otherwise.
Just use this:
<pre v-html="JSON.stringify(objectJs, null, 2)"></pre>

How to get a child collection when the id of the parent isn't in the URL?

I have a Book and a Chapter collection. In a template called book_list.html there's an each statement listing all the book items:
<!-- book_list.html -->
<template name="bookList">
<div class="book-list">
{{#each books}}
{{> bookItem}}
{{/each}}
</div>
In order to get the word count I created a helper in book_item.js which works by fetching all the chapters in the book and returning the sum of all of their words.
Everything was OK, until I decided to remove the autopublish package and use publish and subscribe instead. The problem now is that I don't know how to do get the ID of the current book in book_list since its ID is not present in the URL (book_list is the home page).
This is the code (minus the code for the word count):
//publications.js
Meteor.publish("books", function() {
return Books.find({});
});
Meteor.publish("chapters", function(bookId) {
return Chapters.find({
bookId: bookId
}, {
sort: {
position: 1
}
});
});
//route.js
Router.map(function() {
this.route("bookList", {
path: "/",
waitOn: function() {
return Meteor.subscribe("books");
},
data: function() {
return Books.find({});
}
});
});
//book_item.js
Template.bookItem.helpers({
words: function() {
var chapters = Chapters.find({
bookId: this._id
}).fetch();
// code for the word counter

Categories

Resources