Display the contents of a database query with Node.js and Handlebars - javascript

I am routing from one page to another, and am trying to display the contents of the database query on the next page in my user display.js
exports.list = (req, res) => {
console.log("we have activated userdisplay.js\n");
db.query('SELECT * FROM User', (error, results, fields) =>
{
console.log('we did a query');
if(error)
{
console.log("Error: ",error);
res.send({
"code": 400,
"failed": "Error occurred"
});
} else {
console.log("Results: ",results);
/*res.send({
"code": 200,
"success": "Database successfully logged"
});*/
res.render('tempdisplay.html', {data: results});
}
});
}
So I have the data, but now I need to display it. I tried using handlebars to convert the data object sent by res.render() in the tempdisplay.html file to strings using
<script>
var user = [
{{#each data}}
{
email: '{{email}}',
fname: '{{fname}}',
lname: '{{lname}}',
pass: '{{pass}}'
}
{{/each}}
];
</script>
When I try to run this to convert them to strings it gives me a "Invalid regular expression: missing / in file" Error. This error only happens when this script is present. I have jquery and handlebars included in the file, and my other files work with the pathways/cdn. I don't really seem to understand how I would go about using handlebars to display the data. If I make another js file, I won't be able to see the data object returned to tempdisplay, but if I try to make a handlebars script in the html file it gives me syntax errors.

To display data on the client, the usual method is to insert it into a template on the server:
// fill tempdisplay.hbs with results, send to client
res.render('tempdisplay', {data: results});
An example of a template file tempdisplay.hbs is this:
<table>
<tbody>
{{#each data}}
<tr>
<td>{{this.fname}}</td>
<td>{{this.lname}}</td>
</tr>
{{/each}}
</tbody>
</table>

Related

Get emails that contains attachment using Gmail's API JavaScript

I'm trying to get a list of emails that contain attachments,
I'm getting a list of messages, each message contains 2 properties - id and threadID - I assumed that since the messages do not hold an AttachmentID property, they do not have one either.
I didn't find a way to retrieve only messages with attachments.
This is the code:
function execute() {
return gapi.client.gmail.users.messages.list({
"userId": "myid#gmail.com",
"includeSpamTrash": false,
"maxResults": 100,
}).then(function (response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function (err) { console.error("Execute error", err); });
}
function execute() {
return gapi.client.gmail.users.messages.list({
"userId": "myid#gmail.com",
"q": "has:attachment", // This right here
"includeSpamTrash": false,
"maxResults": 100,
})
.then(
function (response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function (err) {
console.error("Execute error", err)
}
)
}
The "q" parameter has a horde of options you can use to filter the output. This also works in the Gmail UI.
To retrieve only the messages that contains an attachment, you should use the method users.messages.list while including a q parameter to show only messages with attachments. That q parameter can be set up with the string has:attachment. On JavaScript that requests looks like the following:
function execute() {
return gapi.client.gmail.users.messages.list({
"userId": "{ YOUR USERID HERE }",
"q": "has:attachment"
})
.then(function(response) {
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
Please remember to update the userId parameter to match your own scenario.
UPDATE
By reading your new comment I understand that your end goal is to retrieve the attachmentId field. You can do so very easily just by expanding the above request. You only have to keep in mind that the above function returns a message id that can be used to retrieve a Message object containing a MessagePart inside the payload field. That same MessagePart object contains a MessagePartBody object inside the body field. Finally, that MessagePartBody contains the attachmentId field.
To make it clearer I will describe the process step by step:
You run the above users.messages.list function and get multiple id in return.
For each id, you run a users.messages.get function to get a Message object. That function can be similar to this example:
function execute() {
return gapi.client.gmail.users.messages.get({
"userId": "{ YOUR USERID HERE }",
"id": "{ THE MESSAGE ID HERE }"
})
.then(function(response) {
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
The step above will return a Message object with multiple MessagePart inside. Since you are only interested in the attachments MessagePart then you need to interact every one of them checking that the filename field isn't empty (because only attachments MessagePart have a populated filename field). Please bear in mind that there is one MessagePart per every attachment in the email.
Now you have identified which MessagePart contains info about the attachment. Finally, you only need to check the body property of that MessagePart, and read the attachmentId field inside.

How to append data to a JSON with a specific index in javascript/nodejs

I'm doing a basic 'Visitor Book' function.
Users can submit a little form (with three inputs : name, msg and emoji).
I grab it with req.body in my router component. I'm using nodejs, with express and bodyparser.
I only want to store this data in a JSON, don't want any database involved here.
I'm in trouble with the writeFile method, using 'fs' module.
It work but it push the new data outside the single-array of my JSON file.
Do you know if I can push in inside the array ? Like a .push method, but with writeFile/appendFile/wathever that works good with json files.
Here is my code :
app.post (router) :
app.post('/visitorBook', async (req, res) => {
let formData = {
name: req.body.name,
msg: req.body.msg,
emoji: req.body.emoji
}
try {
console.log(req.body)
let data = JSON.stringify(formData, null, 2);
fs.writeFile("./views/scripts/dataVisitorBook.json", data, { { // dataVisitorBook.json is the storage file
flag:'a' // this flag specify 'please append it' over 'please override file'
}
}, (err) => {
console.log('error :', err)
});
res.redirect('/contact')
} catch (error) {
console.error('/visitorBook route error : ', error)
}
})
My JSON :
[
{
"name": "test1",
"msg": "test1",
"emoji": "<i class='fas fa-hippo fa-3x'></i>"
},
{
"name": "test2",
"msg": "test2",
"emoji": "<i class='fas fa-hippo fa-3x'></i>"
}
]
{
"name": "sd",
"msg": "sd",
"emoji": "<i class='fas fa-kiwi-bird fa-3x'></i>"
}
So the last one with "sd" in name and msg is the pushed one. The 2 other are manually written by me, for readFile tests.
I hope I provided all the information needed. Not used to post here...
Thanks you.
If you read from the existing file and parse it with JSON.parse, you will be able to actually use Array.push on it. And then you can write the stringified result back into the file:
fs.readFile("./views/scripts/dataVisitorBook.json", function (err, data) {
if (err) throw err;
let data = JSON.parse(data.toString('utf8'));
data = JSON.stringify(data, null, 2);
fs.writeFile("./views/scripts/dataVisitorBook.json", data, { { // dataVisitorBook.json is the storage file
flag:'a' // this flag specify 'please append it' over 'please override file'
}
}, (err) => {
console.log('error :', err)
});
})
It might not be optimal though as it is likely to take more time as the file grows bigger.
I appreciate your simple try But using some standards can be much better to you
There are some Standard JSON DBs for Node like :
Simple JSON DB
Node JSON DB
Also, you can try SQLite
I also try with a simple JSON file of use as DB. I faced lots of work and I have managed it too. So my advice is to use some standard libraries
Apart from it, you have to get the file data Parse it as JSON (Decoding) make changes and again serialize it and write into a file (Encoding).
[SOLVED]
Thanks to #Divarrek , I've archieved to make it work.
So :
Read the file with fs.readFileSync.
Then, I store this rawdata in a variable, while parsing it to JSON.
THen, I push it in the 'jsonBook' variable which is the json file temporarly made into a simple object-variable.
Then I write in the file with writeFile, passing the data as variable 'parsed', which contain a JSON.stringified version of my 'jsonBook'
app.post("/visitorBook", async (req, res) => {
let formData = {
name: req.body.name,
msg: req.body.msg,
emoji: req.body.emoji,
};
try {
let rawdata = fs.readFileSync("./views/scripts/dataVisitorBook.json");
var jsonBook = JSON.parse(rawdata);
let formDataParsed = JSON.stringify(formData, null, 2);
jsonBook.push(formData);
let parsed = JSON.stringify(jsonBook, null, 2);
fs.writeFile("./views/scripts/dataVisitorBook.json", parsed, (err) => {
if (err) throw err;
console.log("saved");
});
res.redirect("/contact");
} catch (error) {
console.error("/visitorBook route error : ", error);
}
});
I hope I was clear. Maybe I did some explanation error, I'm trying my best.

Express/Mongoose is only saving partial request data to database

I think this is related to how I've defined my schemas, but I can't seem to find where the bug is... I have an almost identical file set up that's working perfectly and I've unfortunately not been able to find a duplicate of this issue anywhere.
When sending an API request to my local Express instance via Postman, only the 'title' request body value is stored in the database. I am sending the following simple request to my route as Application/Json (thought the same happens when using x-www-form-urlencoded):
{
"postTitle": "title goes here",
"postContent": "body goes here",
"isPublished": true
}
This is clearly being registered in express, as if I log the object I can see this data (plus timestamps and an _id):
{ _id: 5b07d9c0b8124e0599079c04,
postTitle: 'title goes here',
postContent: 'body goes here',
isPublished: true,
createdAt: 2018-05-25T09:39:12.869Z,
updatedAt: 2018-05-25T09:39:12.869Z,
__v: 0 }
However, when I send a get request to my route on this object using its ID, I receive the following in response:
{ "_id": "5b07d9c0b8124e0599079c04" }
Likewise, if I send a request to list all objects, I receive the following response:
{
"posts": [
{
"_id": "5b07d9c0b8124e0599079c04"
},
{
"_id": "5b07d9c0b8124e0599079c03"
},
{
"_id": "5b07d9914f10ce058f137eba"
}
]
}
Weirdly, sometimes the post title sent as part of the response is included in the response, and sometimes it isn't.
My schema is as follows:
var postSchema = new Schema({
postTitle: String,
postContent: String,
isPublished: Boolean
},
{
timestamps: true
});
My post API route for POST requests is as follows:
router.post('/posts', (req, res, next) => {
var postTitle = req.body.postTitle;
var postContent = req.body.postContent;
var isPublished = req.body.isPublished;
var newPost = new Post({
postTitle: postTitle,
postContent: postContent,
isPublished: isPublished
});
newPost.save(function (error) {
if (error) {
console.log(error)
}
res.send({
success: true,
message: 'Post saved successfully!'
})
})
});
(If you're not using Router, you'll have 'app.post' instead of 'router.post') Again, this is a bit longwinded but everything works fine.
My GET route is as follows:
router.get('/posts', (req, res) => {
Post.find({}, 'title content published', function (error, posts) {
if (error) { console.error(error); }
res.send({
posts: posts
})
}).sort({_id:-1})
});
OK - so, by going through my code in detail I've figured out where I was going wrong and fixed the issue, however, in my searching I found very little in the way of results. I'm pretty new to Express, so I'm going to outline the cause of the issue and how I resolved it in order to potentially save someone else a bunch of time if they make the same stupid mistake.
Now, the issue I'm having results from the way I was retrieving the data and serving that in response to get requests. As an example, here's my GET route to list all of the objects.
I was entirely focusing on the post request and assuming it was a problem with the database. It turns out what I'd actually done, is in order to make my schemas and routes less confusing, I'd changed the names of the relevant variables. What I'd forgotten to do, however, is update this line in my GET route to reflect the change:
Post.find({}, 'postTitle postContent isPublished', function (error, posts) {
Which I'd left as:
Post.find({}, 'title content published', function (error, posts) {
The reason the title sometimes displayed is that I tried undoing changes back and forth to spot the issue.
I know this is a super basic query but I got stuck on this for the best part of a day, and the only other relevant discussion on this ended with OP saying that it magically fixed itself.

Unable to render data in my view for my express app

I am attempting to get data returned from a database rendered in my web page, but have been unable to do so. I am using using ejs as my templating engine, bookshelf(orm) and express as my node framework.
My model looks like this:
'use strict';
var bookshelf = require('../bookshelf');
var Contact = bookshelf.Model.extend({
tableName: 'contacts',
});
module.exports = Contact;
My controller looks like this:
function list(req, res, next) {
new Contact().fetchAll()
.then(function(contacts) {
var contacts = contacts.toJSON();
var contacts = JSON.stringify(contacts);
console.log(contacts)
res.render('contacts', {
contacts: contacts
});
}).catch(function(error) {
console.log(error);
res.send('An error occured');
})
}
And my template looks like this:
<% include partials/header %>
<h1><%= test %></h1>
<ul>
<% contacts.forEach(function(contacts){ %>
<li><%= contacts.firstName%></li>
<% }) %>
</ul>
<% include partials/footer %>
What I wish to happen is for that for each contact their first name shold be displayed on the page. However nothing is displayed even though the console.log statement (in the controller) displays this in the console:
[{"id":1,"firstName":"tom","lastName":"jones","emailAddress":"joney#test.com"},{"id":2,"firstName":"don","lastName":"jon","emailAddress":"don#test.com"}]
So data is returned from the DB, just not rendered in my view. Can anybody help me out with what I am doing wrong?
Method 2:
Below is a new way I have tried to do this. However this just results in the JSON been displayed on my web page.
function list(req, res) {
Contact.fetchAll()
.then(contacts => res.json({
contacts
})
).catch(function(error){
console.log(error);
res.send('An error occured');
})
}
It seems that bookshelf orm return a collection object, and you can use .toArray() method to transform it to an array and then pass it to your view without calling JSON.stringify, Try this:
function list(req, res, next) {
new Contact().fetchAll()
.then(function(contacts) {
res.render('contacts', {
contacts: contacts.toArray()
});
}).catch(function(error) {
console.log(error);
res.send('An error occured');
});
}
You seem to be double toJSON()-ing your contacts collection. There is no need to call toJSON() explicitly if you're going to call JSON.stringify() afterwards, since that method already calls .toJSON() on its own.
However, that's not the problem here. The real problem is that you're stringifying the collection, meaning it's a string when used on the template, so it's not possible to treat it like an object.
If you just remove the JSON.stringify(contacts); part it should work fine.

MeteorJS Infinite loop when using meteor call and meteor method

I have a sample code that goes like this:
Client Helper:
getUsername: function (userId) {
Meteor.call("getUsername", userId, function (err, result) {
if(!err) {
Session.set("setUsername", result);
else {
console.log(err);
}
});
return Session.get("setUsername");
}
Server
Meteor.methods({
"getUsername": function (userId) {
var x = Meteor.users.find({_id: userId}, {fields: {username:1}}).fetch()[0];
return x.username;
}
});
The result of this code is an infinite loop of username passing to the client. Is there a way to stop the loop and pass only the data that is needed on the client? I believe the reactivity is causing the data to loop infinitely and I am not sure how to stop it. I tried using "reactive":false on my query in the server but it does not work.
If you want to access username everywhere in client templates (so thats why you put it into session), I would not set it in template helper. I would set it on startup and get username from session in template helpers (without calling server method)
If you need username just in one template, so you want to return its value from your template helper, do not put it into session, just return it in your server method callback.
Based on your sample code, I assume, you have a set of posts and you are retrieving user name based on user id for each post. Then instead of doing it this way, you should use publish composite package to publish related users as well.
Meteor.publishComposite('getPosts', function (postIds) {
return [{
find: function() {
return Posts.find({ _id: { $in: postIds }});
// you can also do -> return Posts.find();
// or -> return Posts.find({ /* or what ever your selector is to get the posts you need*/ });
},
children: [{
find: function(post) {
return Meteor.users.find({
id: post.userId //or the correct field in your post document to get user id
}, {
fields: {
"profile": 1
}
});
}
}}
}]
});
This way your publication will take care of publishing related users along with posts. You don't need to use methods and call them each time.

Categories