I have this code that allows me to get all the posts that the user made in my DB. The problem is that I tried to send that data to the front end (client). But I didn't succeed and I don't know what I'm missing,
The code that extracts the user's info from mongoDB is below. Tthe code is working perfectly, no issue with it,
User.find({}).lean(true).exec((err, users) => {
let userMap = [];
userMap.push({ user: users[i], posts: users[i].posts[j] });
//all the data are stored to userMAP :[{user : xxxxx ,posts : {the posts are here}}]
}
}
}
console.log(userMap);
User.findOne({ userName: req.user.userName }, (error, req_user) => {
console.log(req.user.lastLogin)
let lastSeen = ta.ago(req.user.lastLogin);
//console.log(posts)
res.render('home', { // this part for rendering the homePage and send data
user: req_user,
people: users,
userMap: userMap.reverse()
});
});
What I tried in my client side code is this:
<div class="container">
<% for(var x=0;x<user.posts.length;x++) { %>
<div class="jumbotron">
<div>by
<b>{{ user.posts[x].author }}</b>
on
<small>{{ user.posts[x].createdAt }}</small>
</div>
<div>
<p>{{ user.posts[x].caption }}</p>
</div>
<div class="row">
<button onclick="actOnPost(event);"
data-post-id="{{ this.id }}">Like
</button>
<span id="likes-count-{{ this.id }}">{{ this.likes_count }}</span>
</div>
</div>
<% } %>
For the error part I don't get anything,
this is the image of my stored data in the database
and this is the image of the homepage
The scenario for my code :
1- I'm using a EJS view engine and when the user login in the home.ejs is showing up and in the server side I use the code above to prepare the data that I need to display
2- Everything works perfectly except for displaying the data on the client side home.ejs
3- to call that page from my server I used this statement with the mix of the above code
router.get('/home', (req, res) => {
if (req.user.id) {
console.log(req.user.id)
User.find({}).lean(true).exec((err, users) => {
let userMap = [];
Any help or a better solution for showing data at the client side,
Best Regards,
That's not the syntax to display data in ejs ,try this.See these docs
<%= Outputs the value into the template (HTML escaped)
<% for(var x=0;x<user.posts.length;x++) { %>
<div class="jumbotron">
<div>by
<b><%= user.posts[x].author %></b>
on
<small><%= user.posts[x].createdAt %></small>
</div>
<div>
<p><%= user.posts[x].caption %></p>
</div>
<div class="row">
<button onclick="actOnPost(event);"
data-post-id="<%= this.id %>">Like
</button>
<span id="likes-count-<%= this.id %>"><%= this.likes_count %></span>
</div>
</div>
<% } %>
The source code for the template is being rendered in the browser. This means that the view engine is not parsing it.
The default view engine is Jade, but you aren't using Jade.
Probably you forgot to configure the view engine:
app.set('view engine', 'whatever template engine you are trying to use')
Hi #odegeek what show us so far is how are you getting the data from the database and an idea of how to show it in your view. But we are missing a few pieces of information here. For example:
Which frontend framework are you using if any?
Where are you calling the backend endpoint?
Which view engine are you using?
A typical flow for this scenario would be:
You frontend makes a request to your backend asking for the data
Once the response gets to the browser you do some kind of parsing/mapping to adapt it to your needs
Then you pass it to your view for rendering. Now depending on the frontend framework/view engine you are using. The code to render the data will vary
I hope this can give you a idea of what you need to provide/do .. thanks
Related
i am trying to use Leaflet API and store my users saved points(markers,circles,polygons) into a MongoDB database.
Is there a more elegant and dynamic way of writing a JS script in a HTML page while getting the results from the database?
at the moment i am getting my data from Mongo and passing it through the Get request and using that on the HTML page, writing EJS inside the JS script. it works fine but im looking into a better solution.
many thanks for your time
// index.js
router.get('/index', ensureAuthenticated, (req, res) => {
var queryz = Points.find({ belongs_to: req.user._id })
queryz.exec(function (err, results) {
if (err) return handleError(err);
res.render('index', {
user: req.user,
points: results,
})
})
})
// index.ejs
// looping through the points from the database to dynamically add the points
// each time the map is called
<% if(typeof points != "undefined") { %> // making sure user is logged in
<% counter = 1 %>
<% if(points.length>0){ %>
<% points.forEach(p => {%>
<% if(p.type == "marker"){ %> // if point is a marker
marker<%=counter%> = L.marker([<%=p.coords%>], { icon: <%=p.icon%>, alt: '<%=p.popup_message%>' }).bindPopup('<%=p.popup_message%><form method="post" action="/delete_point" id="pointFORM"><input id="pointID" name="pointID" value="<%=p._id%>"><button id="submitBtn" type="submit">🚫</button></form> ').openPopup()
<% counter++%>
<% } %>
<% if(p.type == "circle"){ %> // if point is a circle
marker<%=counter%> = L.circle([<%=p.coords%>], { color: '<%=p.color%>', fillColor: '<%=p.fill_color%>', fillOpacity: <%=p.fill_opacity%>, radius: <%=p.radius%> }).bindPopup('<%=p.popup_message%>').openPopup()
<% counter++%>
<% } %>
<% if(p.type == "polygon"){ %> // if point is a polygon
marker<%=counter%> = L.polygon([<%=p.coords%>], ).bindPopup('<%=p.popup_message%>').openPopup()
<% counter++%>
<% } %>
<% });%>
<% } %>
<% } %>
I'm assuming the problem space here is that you want to dynamically fetch some data from your server and insert that into a web page using Javascript in the web page.
Given that, you have several options:
You can make an Ajax call to your server and have your server return fully formed HTML which your client-side Javascript can then insert directly into the page. That appears to be what you are illustrating already in your question.
You can make an Ajax call to your server and have your server return JSON which your client-side Javascript can then turn into HTML itself and insert that into the page. You can either manually code the conversion into HTML in Javascript or you can use client-side rendering with EJS to convert the data into HTML using a client-side EJS template.
You can reload the entire page and let the server render the whole new page, presumably including the latest data.
For incremental updates to a page, options 1 and 2 are generally preferable to option 3 and are usually more efficient for all.
The choice between 1 and 2 is really just an architectural preference. Some developers of high scale sites would rather offload as much processing to the client as possible and thus prefer letting the client do the rendering of the new HTML as in option 2, but that means you have to have both the EJS template and client-side EJS rendering in the web page which is more client-side weight. So, that's a tradeoff too.
There really aren't options that are simpler than these, so if what you have now (option 1) is working just fine you can stay with that.
I am working with ejs, mongodb and express. In ejs file, I have set value of an Edit button to the the js object passed into the ejs file so that I can query required data after in express after the Edit button makes a post request to a route.
EJS edit button code:
<% listOfRecords.forEach((singleRecord)=>{ %>
<div class="card card-body">
<form method="post">
<button formaction="/edit" class="btn btn-success btn-sm" name="editBtn" value="<%=singleRecord%>">Edit</button>
</form>
</div>
<% }); %>
However, I am able console log the js object by the following code in express:
app.post('/edit', (req, res)=>{
console.log(req.body.editBtn);
});
The output of the above code is:
{
_id: 60605148a1fba61fd8f2446f,
title: 'asdf',
author: 'sadf',
class_section: 'asfd',
dateIssued: 2021-03-01T00:00:00.000Z,
__v: 0
}
But when I try doing this:
console.log(req.body.editBtn.title);
it shows the error, undefined
What am I doing wrong in this?
I don't think we have enough information. The code from my perspective looks fine. It should work.
What you could try doing is getting the attribute by doing console.log(req.body.editBtn['title']); instead of console.log(req.body.editBtn.title);.
You could also try destructuring the title : const { title } = req.body.editBtn.
Although these should theoretically not work !
Maybe something else in your code is wrong ?
Edit:
If req.body.editBtn is a string then try JSON.parse(req.body.editBtn); then get the attribute you want.
The real problem was that req.body.editBtn was in String format. So to make this work, change in EJS file would be:
<button formaction="/edit" class="btn btn-success btn-sm" name="editBtn" value="<%=JSON.stringify(singleRecord)%>">Edit</button>
This shall convert js object into a string properly and then in express file, the change is:
let editBtn = req.body.editBtn;
let info = JSON.parse(editBtn);
Now I can access any property of the object because it was converted to and from string properly.
you should get attributes from JSON.parse method's output, rather than req.body.editBtn which is still string.
app.post('/edit', (req, res)=>{
const data = JSON.parse(req.body.editBtn);
// console.log(req.body.editBtn);
console.log(data.title);
console.log(data.author);
// ....
});
I am needing to have 1 page of a website submit data to MongoDB then pull that same data and display it on a different page. I am using node.js, express, Mongoose, and MongoDB.
Currently, I have it so It gets submitted properly to the database, and I can see it with the correct layout, But I cannot seem to get it posted on the page.
How exactly do I go about doing this?
Can someone give a example of code of this?
I am really new to this stuff and still learning.
Thanks!
In the route of the page you want to load, use the Mongoose .find()
method.
You can use {} in the find() method to return all the data, or access
individual data based on the object key find({id:'value'}). Then when you
render the page, just pass in an object to the render, where the key is
what you access in the url page, in my example you would use
(mongs) to access the values within the url page (.ejs, etc). So in
your route definition file:
app.get('/', (req, res) => {
MongModel.find({}, (err, foundMongModel) => {
err ? console.log(err) : res.render('url/route', { mongs: foundMongModel });
});
});
Then if you're using .ejs file, you would need to use <%= %> to access
individual data, and <% %> to use a loop or something.
and use the mongs value. So if you imported all the data from the
database, you could loop through it using
<% mongs.forEach(mong =>{ %>
<div>mong.key<div>
<% }) %>
You can access the keys for each database object like above using
mong.key
I've created a simple blog site, with posts, users and comments.
I'm using - MongoDB, NodeJS and Express with an EJS view.
I've encounterd a problem when I tried to create the comments sections.
I wanted to use JQuery with Ajax requests in order to make the comments section
so the page won't refresh when a user is posting a comment or edting one.
In order to get the comments for each post, I built an api route that look like this - www.domain.com/api/messages/:post_id
this url returns JSON that contains the comments for that post.
I didn't want to expose 'risky' data about the author of the comment so I fillterd the results with the Mongo query.
Now for the problem -
I want to add edit and delete buttons for each comment, that would show up only for the admin and the author of course.
When I use EJS its simple - I wrote something like this -
<% if (user !== null&& (JSON.stringify(user._id) === JSON.stringify(comments[i].author._id)
|| user.is_admin === true)) { %>
put the buttons here...
The thing is, when I'm using JQuery on my main scirpt file, I can't access the user (that's an object that was sent from Nodejs on the backend).
I'm not sure if I should 'send' this object to my js file from the EJS, I think it's not secure and not the right way.
And I can't also keep that EJS code I quoted a few lines ago because when the EJS file loads there are no comments on that page (the XHR request gets them and JQuery puts them on the page).
So I'm really not sure how to move on.
Edit - I think i have a solution: Maybe I should create an array of IDs on the EJS file that would contain the comments that need to have these buttons, and then I would send that array to the JS file somehow?
Thank you!
So I think I managed to overcome this problem, I'll post what I did so hopefully it will help someone in the future.
In the EJS file, I assigned an array that will hold the ID's of the comments that were published by the current user (The user was sent to the EJS file by the nodejd backend).
Then, I copied this array to a script tag variable in the EJS file, By doing that, I can now access it from the main.js file, and add the delete/edit buttons only to comments that have an ID that's in the array.
<% var arr = []; %>
<% for(var i = 0; i < comments.length ; i++){ %>
<% if (user !== null && (JSON.stringify(user._id) === JSON.stringify(comments[i].author._id) || user.is_admin === true)) { %>
<% arr.push(comments[i].comment_id); %> <% } %>
<% } %>
<script>
var exported_array = <%- JSON.stringify(arr) %>
</script>
Send the user and all comments to the main EJS file.
app.get('/', function (req, res) {
res.render('index', {
comments: [{ ... }, { ... }, { ... }],
user: { ... }
});
});
The comments can be rendered by including a EJS partial comment.ejs from the folder partials in the main EJS file.
<% comments.forEach(function(comment){ %>
<% include partials/comment %>
<% }) %>
In that partial you render the comment and buttons. The comment is past through to the include. The user already lives on the main EJS template.
<div class="comment-container" data-commentid="comment._id">
<p><% comment.content %></p>
<% if (user !== null&& (JSON.stringify(user._id) === JSON.stringify(comment.author._id) || user.is_admin === true)) { %>
<button class="button_delete" data-commentid="<% comments_id %>">delete</button>
<% } %>
</div>
Then create a route in your API like www.domain.com/api/messages/delete/:post_id.
app.get('/messages/delete/:post_id', function(req, res){
// logged on user lives on the server
// check if user may delete comments
// delete comment
// send result
res.send(true);
});
When you click the button use jQuery to send that id from the data attribute of the button to the server/api and from there I would Identify the user that's logged on. If the logged on user is authorized delete it and send back the result. If everything is okay use jQuery to delete the div containing the whole message.
$('.button_delete').click(function(){
// retrieve id from data attribute here
var commentId = $(this).data("commentid");
$.get('www.domain.com/api/messages/delete/' + commentId, {}, function(result){
if(result) {
// delete comment container from html using commentId or refresh
}
});
});
I am using NodeJS and MongoDB.I have a simple app.You type your data to the textarea,when click submit,it creates a new object in a database.Then if you wanna check certain information in your database,you can type to input an id.It will search in the database for the object with the same id and then it will show you the information on the next page.It works nicely.But what i also need,is that if you will send the JSON POST request to my server,let's say,through POSTMAN,i want it to be displayed not as HTML,but as a JSON object.I guess i need to right a middleware that will check the request first,and if it should be html,it will keep running the code that renders an HTML,and if there is JSON request,then it will do another thing.
That's the code that finds the right object by it's id to show on the webpage:
app.post("/insertedids", function(req,res){
var inputid = req.body.emails;
db.collection('emails').find({"_id": ObjectId(inputid)}).toArray(function(err, foundObject){
if(err){
console.log(err)
} else {
res.render("insertedids",{emailslist: foundObject[0].emails});
};
});
});
And this is the code on the page where it shows the data:
<% include partials/header %>
<div class="centeredlist">
<h1>Emails on this ID </h1>
<ul>
<% emailslist.forEach(function(email){ %>
<li><%=email%></li><br/>
<% });%>
</ul>
</div>
<% include partials/footer %>
So i need that if there is a Json request,it will respond by showing a json objects,not an li's.
P.s inpuid that's the name of my input.
P.s.s i am sorry if i made grammar mistakes :D