Use Async function to print value in ejs view Express js - node.js

I passed the model from controller to use it in view, but it seems like printing values using Async functions is not possible in a view. what could be the suitable way to use a model to print inside an async function in a view?
I need to get the userImage from user table.
(ps: use of console.log(userImage) in the same place is working, it's driving me crazy. please help me)
<img src="<% userModel.findById(postData.uid,function(err,user) {%> <%=user.userImage%> <% }) %>" class="mx-2">Anmol D. Pradhan

At first, that's absolutely not the best practice.
You should do something like that:
// ...
const userModel = require('/your-path-to/userModel');
app.get('/your/url', async (req, res) => {
const user = await userModel.findById(uid);
res.render('/youpage.html', {
user: user
});
});
<!-- Here's your EJS template -->
<img src="<%= user.userImage %>" class="mx-2">Anmol D. Pradhan
That's just an example. I don't know how actually your routes structured, but I hope that will help.

Related

Cascading Template Use in mustache-express?

My intent is to define a page_layout template and a form template as well. Within the route handler i was going to parse the inner (form) template and inject into the greater layout than return.
After several plot twists i'm able to use the response.app to get access to my mustache template engine and parse a view, but the HTML is getting escaped :(
let router = require('express').Router();
let mustache = require('mustache');
router.get('/plant', function(request,response) {
response.app.render('plantForm', {pageTitle: "Plant"},function (err, html) {
response.render ('layout', { pageContent : html});
});
});
yields the outer template with escaped html where I expect content:
<div class="form-group">
<label for="plantNameInput">Plant Type</label>
Perhaps I'm misusing the technology?
From the Mustache documentation:
All variables are HTML escaped by default. If you want to return unescaped HTML, use the triple mustache: {{{name}}}.

POST FORM in node and receive data response back to same webpage

I have a webpage that takes form details, POSTS the data and should then show the results. I'm using express for my routing.
This all works fine by resending the data with the HTML template after the POST but I think there must be a better way by hiding the "results" HTML section then just showing it once the data is known from the form. I've shown a cutdown version of my pages below.
On first load, the page says "your result is undefined", which I would expect but is ugly.
I could remove the "result" section and create a 2nd HTML page to resend from the POST route with it in which would work but I think there must be a better way.
I want to hide the result section on 1st page load then make it appear on the button submit with the result data. I can get the section hide/unhide but I can't get the data results back to display them. On button submit the form results just appear in the weburl www.mywebsite.com/?data almost like a GET request
I have tried using FormData and npm 'form-data' in a POST but can't get it working following these examples https://javascript.info/formdata and https://www.npmjs.com/package/form-data.
My structure in Node is
Router.js file
return res.send(htmlFormTemplate({}));
});
router.post('/css',
[],
async (req, res) => {
let {data} = req.body;
///
result= do some calculation on {data}
///
return res.send(htmlFormTemplate({result}));
});
The htmlFormTemplate is a js file
module.exports = ({result}) => {
return `
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<form class="box" method ="POST">
<inputname="data" />
<button>Submit</button>
</form>
<script>
///tried form processing here
</script>
<section id="Results">
<ul><li>Your result is ${result}</li></ul>
</section>
</body>
</html>
`;
};
I'm self-taught and new so hope this makes sense and thanks for any help/ideas
You can check if the result variable is null before it gets to the section div:
${ result === null ? '' :
`<section id="Results">
<ul><li>Your result is ${result}</li></ul>
</section>`}
Like this, it wont show the result div if result if null.
There is a very simple to solve this problem,
just use some templating engine for ex EJS, its very easy to use and will help you better,
and your result is undefined because your using a promise and it might have happened that the response might have not come and you loaded the page. Just use await
return await res.send(htmlFormTemplate({result}));

Rendering elements classname in client-side without JS framework? (EJS)

Let's say I have an app which shows to the users a list of existing hobbies.
Each hobby has a category, stored in the db.
I want every hobby element to have its background color - dependent on its category.
I want to implement this with appending specific class to each element.
Basic example code:
Server
app.get("/hobbies", (req, res) => {
const hobbies = Hobby.getAllHobbies();
res.render("hobbies", hobbies);
});
Client (EJS)
<% hobbies.forEach(hobby => { %>
<div class=""><%= hobby.name %></div>
<% }); %>
What is the best way to append to each div a class depending of hobby.category?
I know its easily possible in React, but I don't want to use any framework for now.
If your classname is not the same as the category but is based on it, then you just need to pass a lookup object to your template.
Server
const categories_classnames = {
lookup: {
swimming: 'div-swim',
biking: 'div-bike',
painting: 'div-paint',
// ...
}
};
app.get("/hobbies", (req, res) => {
const hobbies = Hobby.getAllHobbies();
// Alternatively, `locals = { ...hobbies, ...categories_classnames }`
const locals = Object.assign({}, hobbies, categories_classnames);
res.render("hobbies", locals);
});
Client
<% hobbies.forEach(hobby => { %>
<div class="<%= lookup[hobby.category] %>"><%= hobby.name %></div>
<% }); %>

Redirect and render template with new variables

I will show my code first in order to be clear.
router.get("/add", (req, res)=>{
res.render("user/add.ejs");
});
router.put("/add/pi", (req, res)=>{
if(condition){
//do something
}else{
res.redirect("/user/add");
//res.render("user/add.ejs", {error: "At least one field should be filled in order to submit the form", type: "form error","location": "form-container"});
}
});
Ejs:
<% if(error){ %>
<small id="personalinformationError" class="form-text text-danger"><%= error %></small>
<% }%>
I want to be able to render the ejs template with the object in the render() in the comment. I tried to render it like in the comment without redirect() and it shows an error whenever I mention the variable name. The error goes like variable is not defined.
Thank you in advance.

Pass variable to EJS include

I have a global header used in a couple of places and I was trying to define its location in a variable that could be passed when rendering a template.
Something like:
var headerLocation = 'some/location/header.ejs';
res.render( viewDir + '/index', {
header: headerLocation
} );
And in a template file:
<% include header %>
header being the value passed in with the render.
It doesn't seem to be possible but maybe I missed something so thought I'd ask here.
EDIT:
This is mentioned in comments on answers below but to summarize, this is now available in version 2 of EJS.
See here: https://github.com/mde/ejs#includes
And related discussion here: https://github.com/tj/ejs/issues/93
Here is some demo code that can accomplish dynamic includes.
View
<div flex class="main-container">
<%- include(page) %>
</div>
Router
router.get('/', function (req, res, next) {
res.render('pages/index', {
page: 'home'
});
});
This feature has been added: if it is not path (file not found), it is evaluated as variable name. https://github.com/visionmedia/ejs/pull/156
Even though its an old question, answering it for others sake.
As per the github documentation, it seems EJS has no notion of blocks, only compile-time include. Since its compile time include, you need to hardcode the location.
So you are left with passing some flags and doing if checks in the header or parse the header as html and pass it to all the templates...
Old subject, but it may help someone.
The great thing about EJS is that it is just Javascript. So something like the following should work:
<%
const fs = require('fs');
const content = fs.readFileSync(partial);
%>
<%- content %>
Hope it helps.

Resources