How can I pass variable to ejs.compile - node.js

My bottom_index.ejs looks like that:
<div>The bottom section</div>
In my code I declare ejs:
ejs = require('ejs');
Then compile the function:
var botom_index_ejs =
ejs.compile(fs.readFileSync(__dirname + "/../views/bottom_index.ejs", 'utf8'));
and then call it to get rendered html:
botom_index_ejs()
It works fine!
Now I would like to change my template to:
<div><%= bottom_text %></div>
and be able to pass the parameter (bottom_text) to the bottom_index.ejs
How should I pass the parameters?
Thanks!

Parameters are passed to EJS template as a JS plain object. For your example it sholud be:
botom_index_ejs({ bottom_text : 'The bottom section' });
Update:
test.js
var fs = require('fs');
var ejs = require('ejs');
var compiled = ejs.compile(fs.readFileSync(__dirname + '/test.ejs', 'utf8'));
var html = compiled({ title : 'EJS', text : 'Hello, World!' });
console.log(html);
test.ejs
<html>
<head>
<title><%= title %></title>
</head>
<body>
<p><%= text %></p>
</body>
</html>

Related

How to render html file inside of .ejs file

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

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

How to set a variable for the main handlebars layout without passing it to every route?

I'm using handlebars with nodejs and express. This is my main.handlebars file:
<!doctype html>
<html>
<head>
...
</head>
<body>
<div class ="container">
...
<footer>
© {{copyrightYear}} Meadowlark Travel
</footer>
</div>
</body>
</html>
So far I'm passing the copyright year to every route:
var date = new Date();
var copyrightYear = date.getFullYear();
app.get(
'/',
function( req, res) {
res.render(
'home',
{
copyrightYear: copyrightYear
}
);
}
);
Is it possible to set the copyrightYear variable globally, so I don't have to pass it on to every route/view?
ExpressJS provides some kind of "global variables". They are mentioned in the docs: app.locals. To include it in every response you could do something like this:
app.locals.copyright = '2014';
For this case, you can alternatively create a Handlebars helper. Like this:
var Handlebars = require('handlebars');
Handlebars.registerHelper('copyrightYear', function() {
var year = new Date().getFullYear();
return new Handlebars.SafeString(year);
});
In the templates, just use it as before:
© {{copyrightYear}} Meadowlark Travel
Using express-handlebars is just a little bit different:
var handlebars = require('express-handlebars').create({
defaultLayout:'main',
helpers: {
copyrightYear: function() {
return new Date().getFullYear();
},
}
});

template not rendering correctly

Can someone please point me in the right direction. I tried google and didn't find much regarding my issue. While the following code works perfectly fine when running the .html file directly, it doesn't while serving the file in a node express app. The problem is that with node I don't see any data. page loads fine but no data.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="jquery.js"></script>
<script src="handlebars.js"></script>
<script src="underscore.js"></script>
<script src="backbone.js"></script>
<script src="moment.js"></script>
<!-- Setup our templates -->
<script id="PersonTemplate" type="text/x-handlebars-template">
<div>
Person:<br>
{{name}}
{{age}}
</div>
</script>
<!--
Note the [] this is important
because handlebars and backbone collections
dont play well with each other in regards
to naming JSON groups
-->
<script id="PeopleTemplate" type="text/x-handlebars-template">
<div>
People:<br>
{{#each []}}
{{this.name}}
{{this.age}}
<br/>
{{/each}}
</div>
</script>
<!-- End templates setup -->
<script>
// Stub out the person model
var Person = Backbone.Model.extend({
});
// Create a collection of persons
var People = Backbone.Collection.extend({
model: Person
});
// Define the view for a single person
var PersonView = Backbone.View.extend({
render: function() {
// This is method that can be called
// once an object is init. You could
// also do this in the initialize event
var source = $('#PersonTemplate').html();
var template = Handlebars.compile(source);
var html = template(this.model.toJSON());
$(this.el).html(html);
}
});
// Define the view for People
var PeopleView = Backbone.View.extend({
render: function() {
// This is method that can be called
// once an object is init. You could
// also do this in the initialize event
var source = $('#PeopleTemplate').html();
var template = Handlebars.compile(source);
var html = template(this.collection.toJSON());
$(this.el).html(html);
},
initialize: function(){
this.collection.on('add', this.render, this)
}
});
// Create instance of People Collection
var people = new People();
// Create new instances of the person models
var person = new Person({name: "Tim", age: 5});
var person2 = new Person({name: "Jill", age: 15});
// Create instances of the views
var personView = new PersonView({
model: person
});
var peopleView = new PeopleView({
collection: people
});
$(document).ready(function(){
// We have to do this stuff in the dom ready
// so that the container objects get built out
// Set el of the views.
personView.el = $('#personContainer');
peopleView.el = $('#peopleContainer');
// Add them to a new instance of the people collection
people.add(person);
people.add(person2);
// Render the views. If you are using the initialize
// method then you do not have to do this step.
personView.render();
//peopleView.render();
// Try on console!
// people.add(new Person({name: 'Rames', age:'23'}));
});
</script>
</head>
<body>
<div id='personContainer' ></div>
<hr>
<div id='peopleContainer' ></div>
</body>
</html>
Thanks in advance for your help.

is there a way to add CSS/JS later using EJS with nodejs/express

i'm using the EJS template engine with nodejs/express and i'm wondering if it's possible to add another css or js file in e.g the index.ejs (not the layout.ejs)
layout.ejs
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
<link rel='stylesheet' href='/stylesheets/smoothness/jquery-ui-1.8.14.custom.css' />
</head>
<body>
<%- body %>
</body>
</html>
index.ejs
<h1><%= title %></h1>
<p>Welcome to <%= title %></p>
i don't want to add the second css file in every template but only the index.ejs - is there any way i can do that?
found a solution here: Node.js with Express: Importing client-side javascript using script tags in Jade views?
it's using jade instead of EJS but works all the same.
here are some code-snippets for express 2.4.0.
you have to add the following "helpers" to your app.js
app.helpers({
renderScriptsTags: function (all) {
if (all != undefined) {
return all.map(function(script) {
return '<script src="/javascripts/' + script + '"></script>';
}).join('\n ');
}
else {
return '';
}
}
});
app.dynamicHelpers({
scripts: function(req, res) {
return ['jquery-1.5.1.min.js'];
}
});
the layout.ejs looks sth like this:
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
<%- renderScriptsTags(scripts) %>
</head>
<body>
<%- body %>
</body>
</html>
if you don't add any scripts to the scripts-array, only 'jquery-1.5.1.min.js' will be included - if you want to add files to a subpage you can do this like so:
test.ejs
<% scripts.push('jquery-ui-1.8.14.custom.min.js', 'jquery.validate.min.js') %>
<h1><%= title %></h1>
<p>I'm a template with 3 js files in the header</p>
that's it.
As helpers and dynamicHelpers are gone in Express > 3, I rewrote pkyeck code so it works in Express 3.
So in app.js have this instead of the helpers / dynamicHelpers. Leave everything else as is.
app.locals({
scripts: [],
renderScriptsTags: function (all) {
app.locals.scripts = [];
if (all != undefined) {
return all.map(function(script) {
return '<script src="/javascripts/' + script + '"></script>';
}).join('\n ');
}
else {
return '';
}
},
getScripts: function(req, res) {
return scripts;
}
});
In app.js add line:
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/public')); // This line.
In layout.ejs:
<!DOCTYPE html>
<html>
<head>
<title>Authentication Example</title>
<link rel="stylesheet" href="/stylesheets/style.css"/>
<script src="/javascripts/jquery.js"></script>
</head>
<body>
<%- body %>
</body>
</html>
In index.ejs or login.ejs:
<h1>Login</h1>
<form method="post" action="/login">
<p>
<label>Username:</label>
<input type="text" name="username">
</p>
<p>
<label>Password:</label>
<input type="text" name="password">
</p>
<p>
<input type="submit" value="Login">
</p>
</form>
<script src="/javascripts/test.js"></script> <!-- Second Script -->
In test.js:
$(document).ready(function() {
try{
alert("Hi!!!");
}catch(e)
{
alert("Error");
}
});
Regards.
Thanks #asprotte for providing this for express 4.x. Did you tested this?
Because it does not appears to be working for me. So I have made some changes to your code here are they:
Put this in app.js file
app.locals.scripts = [];
app.locals.addScripts=function (all) {
app.locals.scripts = [];
if (all != undefined) {
app.locals.scripts = all.map(function(script) {
console.log(script);
return "<script src='/js/" + script + "'></script>";
}).join('\n ');
}
};
app.locals.getScripts = function(req, res) {
return app.locals.scripts;
};
then in template file put (I am using ejs template here) :
<% addScripts(['cart.js']) %>
Then in the layout file we need these to append at the bottom of the page get the scripts
<%- getScripts() %>
I have tested it and its working for me. Please correct me if I am wrong.
Thanks,
Thanks for illustrating this option pkyeck!
In express 4.x app.locals is an object. Here's pkyeck's answer rewritten to work in express 4.x:
app.locals.scripts = [];
app.locals.addScripts=function (all) {
app.locals.scripts = [];
if (all != undefined) {
return all.map(function(script) {
return "<script src='/javascripts/" + script + "'></script>";
}).join('\n ');
}
else {
return '';
}
};
app.locals.getScripts = function(req, res) {
return scripts;
};

Resources