How to render html file inside of .ejs file - node.js

I want to load a default header on a .ejs file.
I asked ChatGPT but it didnt give me the correct code.
This is the index.ejs file that is being send over email:
<!DOCTYPE html>
<html>
<head>
<title>My Web Page</title>
</head>
<body>
<% include header %>
<h1>Welcome to My Web Page</h1>
</body>
</html>
ChatGPT said to use the tag <% include header %> but that didnt work.
These two fields are in the same folder.
The header.html file is the following:
<header>
<nav>
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</nav>
</header>
Is there any way to render html inside a .ejs file?
Below is the actual code that sends the email:
async function sendEmails(winningCampaigns) {
fs.readFile('backend/views/index.ejs', 'utf-8', async (err, data) => {
if (err) throw err;
let html = data.replace(/{{name}}/g, 'John Doe');
for (let campaign of winningCampaigns) {
sendEmail({
to: "jcasasmail#gmail.com",
subject: "Hello ✔", // Subject line
html: html
})
}
});
}

For starters, there's no purpose for the async keyword if the function doesn't use await. Any code that awaits sendEmails won't actually wait for readFile to resolve because it's callback rather than promise-based. Consider using fs.promises.readFile here, or better yet, use EJS's built-in renderFile.
On to the main point, your code doesn't run EJS at all. fs.readFile doesn't treat the file as a template, even with an .ejs extension.
data.replace(/{{name}}/g, 'John Doe'); defeats the purpose of EJS, which should be doing the templating. You're probably in a testing phase, but name isn't used in the template.
You can use <%- include("header.html") %> in EJS to include a .html file, which should be in the same directory as the EJS template.
Here's how I'd approach the sendEmails function:
const ejs = require("ejs"); // ^3.1.8
const path = require("path");
async function sendEmails(winningCampaigns) {
const p = path.join("backend", "views", "index.ejs");
const html = await ejs.renderFile(p, {name: "John Doe"});
for (const campaign of winningCampaigns) {
sendEmail({
to: "<Your email address>",
subject: "Hello ✔",
html,
});
}
}
Note that I'm using path.join() rather than string concatenation to build system-agnostic paths.
If sendEmail is async, be sure to await that as well.
My file structure is:
├── backend
│ └── views
│ ├── header.html
│ └── index.ejs
└── send-emails.js

Related

How do i make the ejs variable work that i send from nodejs?

I am tring to get a variable that i send from nodejs to ejs to work. But for some reason it wont, i cant figure out why.
This is the index.js:
var newOne = "Yes"
router.get('/main', ensureAuthenticated, (req, res) =>
res.render('main', {
user: req.user,
newOneInView : newOne
})
)
And this is in the main.ejs file:
<%if (newOneInView == "Yes") { %>
document.getElementById("avatar").src = "/static/images/Apocaliptic1.png";
<% } %>
So what i am trying to achieve is that variable will be seen from the nodejs at the main.ejs page but some reason it wont change the image SRC. What am i doing wrong here?
In your template you need to make sure that you place the code for changing the src attribute in a script that is placed after the element (alternatively you can use a listener for the content to be loaded), e.g:
<body>
<img id="avatar" src="/some-other-path"/>
<script>
<% if (newOneInView === "Yes") { %>
document.getElementById("avatar").src = "/static/images/Apocaliptic1.png";
<% } %>
</script>
</body>

hbs rendered site with handlebars.js in the script - nodejs

I use hbs to render my pages with partials for navigation and footers.
router.get('/test', function (req, res) {
return res.render('test');
});
On one page I have template that uses mustache.js. This template doesn't work as it should as the {{}} seems to be picked up on the hbs render. Below is a basic example that illustrates the error. If I load this as a static page with express I get "Joe is a Web Developer", if I render it with hbs I get "is a".
Are there any work arounds that wont involve me changing how all my pages are rendered?
<!doctype html>
<html lang="en">
<head>
<title>Mustache.js Inline Method</title>
<script type="text/javascript" src="js/libs/mustache.js" ></script>
<script>
var view = {
name : "Joe",
occupation : "Web Developer"
};
function loadtemp(){
var output = Mustache.render("{{name}} is a {{occupation}}", view);
document.getElementById('person').innerHTML = output;
}
</script>
</head>
<body onload="loadtemp()" >
<p id="person"></p>
</body>
</html>
It was simple enough. I just had to escape the brackets with a \
So all it took was
\{{name}}

Client side and Server side rendering of ejs template

I always wanted to learn NodeJS to be able to run the same code on server and client side.
I am using NodeJS with Express and EJS.
So. I have a .ejs page with lot's of HTML, JS, CSS and a small bit with template. For the sake of justice let it be like this:
the_list-->some.ejs
<ul>
<% for(i=0;i>the_list.length;i++) { %>
<li>the_list[i]</li>
<% } %>
</ul>
After some rendering on the server we have a perfect list.
So.
Now I want to rerender it on the client. I made some ajax request and now I have new items in the_list. What is the right way?
As per ejs templates documentation
var template = new EJS({
text: `
<ul>
<% for(i = 0; i < the_list.length; i++) { %>
<li>the_list[i]</li>
<% } %>
</ul>
`
});
var html = template.render({ the_list: data });
document.getElementById('list-wrapper').innerHTML = html;
<div id="output"></div>
<script src="/assets/js/ejs.js"></script>
<script>
let blogPosts = [
{
title: 'Perk is for real!',
body: '...',
author: 'Aaron Larner',
publishedAt: new Date('2016-03-19'),
createdAt: new Date('2016-03-19')
},
{
title: 'Development continues...',
body: '...',
author: 'Aaron Larner',
publishedAt: new Date('2016-03-18'),
createdAt: new Date('2016-03-18')
},
{
title: 'Welcome to Perk!',
body: '...',
author: 'Aaron Larner',
publishedAt: new Date('2016-03-17'),
createdAt: new Date('2016-03-17')
}
];
var html = ejs.render(`<% for(let i = 0; i < posts.length; i++) { %>
<article>
<h2><%= posts[i].title %></h1>
<p><%= posts[i].body %></p>
</article>
<% } %>`, {posts: blogPosts});
// Vanilla JS:
document.getElementById('output').innerHTML = html;
</script>
download ejs.js or ejs.min.js from latest version
Sure, EJS works on the client. You can trivially keep the template in a string variable or apply EJS to user-provided input, but more likely, you'll want to store a template in a script (which can be in an external file) or use fetch to grab your template from another file on demand.
Using a template in a <script> is straightforward:
const people = ["geddy", "neil", "alex"];
const template = document
.querySelector("#template")
.innerText;
document.querySelector("#output")
.innerHTML = ejs.render(template, {people});
<!-- could be an external file -->
<script id="template" type="text/template">
<%= people.join(", "); %>
</script>
<div id="output"></div>
<script src="https://unpkg.com/ejs#3.1.8/ejs.min.js"></script>
For fetch, I'll mock the response so it'll be runnable in a snippet:
// mock fetch for illustrative purposes;
// its response content would be another file
fetch = async url => ({text: async () => '<%= people.join(", "); %>'});
fetch("/your-template")
.then(res => res.text())
.then(template => {
const people = ["geddy", "neil", "alex"];
document.querySelector("#output").innerHTML =
ejs.render(template, {people});
});
<script src="https://unpkg.com/ejs#3.1.8/ejs.min.js"></script>
<div id="output"></div>
If this seems like too much heavy lifting, you can bury the fetch in a helper function, or go a step further and pick an attribute for each URL, then plug everything in with a call to a library function you can abstract away from the main code. A simple example:
// mock fetch for illustrative purposes;
// its response content would be in other files
const responses = {
"/template.ejs": "<%= 42 %>",
"/other-template.ejs": "<%= 43 %>",
};
fetch = async url => ({text: async () => responses[url]});
[...document.querySelectorAll("[data-template]")]
.forEach(e => {
fetch(e.getAttribute("data-template"))
.then(res => res.text())
.then(template => {
e.innerHTML = ejs.render(template);
});
});
<script src="https://unpkg.com/ejs#3.1.8/ejs.min.js"></script>
<div data-template="/template.ejs"></div>
<div data-template="/other-template.ejs"></div>
Either way, keep in mind that JS will run after the static HTML is parsed and the DOM loads. This means the data won't appear all in one fully-formed piece as when using EJS on the server. Network errors are possible.
See also using ejs partials from express client side. If you want to mock the include function, the problem is that the fetch call is asynchronous but the include function isn't. EJS offers an include callback that seems like it offers an opportunity to pull in an external file, but it's purely synchronous and won't await any promises you return. How to work around this best depends on your use case.
This should work, looks like your problem was the relational operator '>' because it will never output something.
<ul>
<% for(var i=0; i<the_list.length; i++) { %>
<li>
<a>
<%= the_list[i]%>
</a>
</li>
<% } %>
</ul>

Node Express EJS Dynamic template render

Hi I am trying to create dynamic template system in express, where I will get dynamic content from database and then render output in single index.ejs file.
Here is my index.js
router.get('/', function(req, res, next) {
var dataFrmDB = {
pageContent: "<%= data.pageTitle %>",
pageTitle: "home"
};
res.render('index', {data:dataFrmDB} );
});
And index.ejs contains:
<%= data.pageContent %>
What I should do so that I can render "home" as output. Is this possible?
I was working on something similar when we migrated from drupal to nodejs, I used ect for rendering instead of jade, its faster and much easier to deal with, However, its much better to use design pattern if you have a big dynamic website
js controller file
model.homepage(function(data)
{
res.render("homepage.ect",data,function(err,html)
{
// Do something before you send the response such as minification, or error handling
res.send(html);
});
});
ECT file
<html xmlns="http://www.w3.org/1999/xhtml" lang="ar" xml:lang="ar">
<head>
<%- #page.title.body %>
<%- #page.headerScript.body %>
<style type="text/css">#homepage-container{min-height:300px;color:#353535;float:right;width:100%}</style>
</head>
<body>
<% include 'upper_bar.ect' %>
<%- #page.headerAd.ads %>
<%- #page.notifications.body %>
<%- #page.autocomplete.body %>
<%- #page.redirect.body %>
<%- #page.navigation.body %>
<%- #page.overlayAd.ads %>
</body>
</html>
why bother so much?
You can easily do this using templatesjs
without any template engine.
let me show you how your work can be done using templatesjs
html file
<html>
<head>
<title> <%title%> </title>
</head>
<body>
your content goes here
</body>
</html>
now use templatesjs in you node.js file
var tjs = require("templatsjs");
router.get('/', function(req, res, next) {
var data = fs.readFileSync("./index.html");
tjs.set(data); // invoke templatesjs
var output = tjs.render("title","home");
/* this will replace the <%title%> tag
in the html page with actual title*/
res.write(output);
res.end()
});
i have used fs.readFileSync to keep simplicity of code you can use the asynchronus function if you want (fs.readFile).
a good referrence can be found here
Installation :
$ npm install templatesjs

node/express retrieving html templates from mongodb

Hi I'm new to node and I'm trying to make a simple blog.
I want to route /pages/:post to search a database for "post" and return an html template file that I can use as a partial.
var posts = {
'myarticle': {
template: partial1.html
}
};
var findPost = function (post, callback) {
if (!posts[post])
return callback(new Error(
'No post matching '
+ post
)
);
return callback(null, posts[post]);
};
app.get('/pages/:post', function(request, response) {
var post = request.params.post;
findPost(post, function(error, post) {
if (error) return;
return response.render('posttemplate', post);
});
});
and posttemplate is a template file like ejs (i'm not comfortable with Jade as of yet) that looks like
<html>
<% include ../partials/header %>
<body>
<% include /thereturnedpost %>
</body>
</html>
Is this possible? I've looked through documentation/tutorials but none of them are clear.
I'l answer with codes examples from my current project
<body>
<%- body %>
<script type="text/javascript" src="/vendors.js"></script>
<script type="text/javascript" src="/main.js"></script>
</body>
and
res.render('index', {
body: content
});
So your example is almost correct. After fetching the data from the database you send it to render function (in my case I render content ).
It is for the case when you keep in the db html string.
Also I can recommend you to use markdown (e.g. markdown-js) for the blog posts. It may be simpler to write and edit well formatted content, and less information to keep (comparing to html).
As per your coding, your blog post contents are static and are in template htmls.
If you get the data from db, you should modify your code such that the template file is with the HTML markup/ejs variables and send the data values separately.
This can be accomplished through ejs.renderFile method...https://www.npmjs.com/package/ejs2
Hope it will help you...

Resources