How to include ejs partials with JavaScript? - javascript

I am writing some code which checks if a user has logged in. And if a user is logged in, the "my user" section should be different from when that user was not logged in.
So when the logged-in user enters the "my user" page, an if statement checks for if the user has logged in or not, and if the user is logged in, it should include a partial that corresponds to the logged-in state. If the user has not logged in, the if statement should include a different partial.
How do I include partials in a div using JS?
I have tried to use parentElement.innerHTML = "<%= include userNotLoggedIn.ejs %> without luck, and I have also tried to manually edit the html file while it runs in the browser using the inspect tool, but it doesn't fetch the template.
It seems like I can't include partials after the main html file has been rendered. Is this the case?
Here is my code:
if(document.getElementById("loginState").innerHTML == " Logg inn") {
//Append the correct html template if the user is not logged in
var includeStr = "<%= include notLoggedIn.ejs %>";
cont.innerHTML = includeStr;
} else {
//Append the desired html template if the user is logged in
var includeStr = "<%= include userLoggedInMenu.ejs %>";
cont.innerHTML = includeStr;
}
where cont is the container in which the template should be added to
I would expect the partial to be added to the container element, and that my notLoggedIn.ejs file is displayed in the html page. This is not the outcome, however.
Please check out the image below: (I can't post images directly into the post)
https://imgur.com/a/ISDFIPp

ejs gets rendered on the server side and gets sent back to the client as HTML. Id don`t think you can add in ejs at the client side.
One possible way to achieve what you are trying would be to set a variable called currentUser and the pass it on to the ejs file and in the file you would set a condition like below to conditionally display content.
// Making the logged in user available
app.use(function (req, res, next) {
res.locals.currentUser = req.user;
next();
});
<% if(!currentUser) { %>
// If the user is not logged in
<% } else { %>
// If the user is logged in
<% } %>

Related

Writing EJS in JS script dynamically

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.

How to submit data then post on another page mongoDB/Node.js

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

Show flash message from server.js to html in particular div with id

I get an error message from server.js and it gets display using 'connect-flash' but it gets redirected with blank page. I want to show the message on same page in a specific div with id in html.
Here is my server.js code
app.get('/', function (req, res) {
// var username = req.body.
if (global.debugMode) debugger;
console.log("userLogin.html".grey);
var loginmsg = req.flash('error');
if(loginmsg.length>0){
console.log(loginmsg);
res.send('<h3>'+loginmsg+'</h3>');
}
res.sendFile(`${path.dirname(__dirname)}//public/Login/userLogin.html`);
});
I want to show 'loginmsg' in specific div on same page but it disaplay on blank page
Your problem comme from express understanding i think. You get a blank page with your flash message in a <h3> ? It's because you do a res.send when you have a flash message. We can only send one response for one request (https://www.webnots.com/what-is-http/), or here you try to send first the h3 then send your html file. It's not the good way to do such things.
First solution
With your solution, the only way to do what you whant is to build the html string dynamically :
var myHtml = `<html><head>...</head><body>`
if(loginmsg.length > 0) { myHtml += `<h3>${loginmsg}</h3>` }
myHtml += `rest of my page ...`
myHtml += `</body></html>`
res.send(myHtml)
But it's clearly no the good practice to do this.
Good practice
Use templates ! (http://expressjs.com/en/guide/using-template-engines.html). With template you can build an html page with dynamic values in it, like your flash message ! With ejs template (https://www.npmjs.com/package/ejs) you will have a .ejs file template like that :
<html>
<head>...</head>
<body>
<% if (loginmsg) { %>
<h3><%= loginmsg %></h3>
<% } %>
Rest of my page...
</body>
</html>
And in your express app :
app.get('/', function (req, res) {
var loginmsg = req.flash('error');
...
res.render('myTemplate', { loginmsg });
});
Have fun ✌️

Sharing Server Side data to a JS file

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

Access Java object in JSP

I have some JSP code I'm trying to modify.
I have a user object that holds and generates a CSRF values. Currently, this value is set at the start of the application and remains constant throughout the application. I have to change this such that it resets each time a new page is accessed.
The code currently is
<script type='text/javascript'>
var csrfTokenName = 'csrfValue';
var csrfTokenValue = '${user.csrfValue}'; //user is the object, which also contains a setCsrfValue() method that generates the CSRF value
var csrfParam = {csrfValue : csrfTokenValue};
function csrfUrl(url) {
if (url.indexOf('?') == -1) {
//setCSRF code here
return url+'?'+csrfTokenName+'='+csrfTokenValue;
} else {
//setCSRF code here
return url+'&'+csrfTokenName+'='+csrfTokenValue;
}
}
</script>
I tried adding this
<%
User user = (User) session.getAttribute('user'); //fixed typo
%>
In the script but the page won't load (on that note, is there a tool/setting for debugging JSP, using STS with Tomcat and Firefox)
How do I reference this object correctly so that I can call setCsrfValue();
I tried the following but the page didn't load
<%
User user = (User) session.getAttribute('user'); //fixed typo
user.setCsrfValue();
%>

Categories