is there a way to add CSS/JS later using EJS with nodejs/express - node.js

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

Related

How to escape '-' hyphen symbol from xml in MathJax

<!DOCTYPE html>
<html>
<head>
<title>MathJax MathML Test Page</title>
<script type="text/javascript" id="MathJax-script" async
src="https://cdn.jsdelivr.net/npm/mathjax#3/es5/mml-chtml.js">
</script>
</head>
<body>
<p>
<math overflow="scroll"><mfrac><msup><msub><mi mathvariant="-italic">Q</mi><mrow><msub><mi mathvariant="italic">T</mi><mi mathvariant="italic">i</mi></msub><mo mathvariant="italic">max</mo></mrow></msub><mn mathvariant="normal">0.75</mn></msup><msup><mi mathvariant="italic">β</mi><mn mathvariant="normal">0.75</mn></msup></mfrac><mo>≤</mo><mn mathvariant="normal">5</mn><mo>×</mo><msub><mi mathvariant="italic">AEL</mi><msub><mi mathvariant="italic">T</mi><mi mathvariant="italic">i</mi></msub></msub><mo>×</mo><msup><msub><mi mathvariant="italic">Q</mi><msub><mi mathvariant="italic">T</mi><mi mathvariant="italic">m</mi></msub></msub><mrow><mo>−</mo><mn mathvariant="normal">0.25</mn></mrow></msup><mo></mo></math>
</p>
</body>
</html>
Getting parsing error with new CDN https://cdn.jsdelivr.net/npm/mathjax#3/es5/mml-chtml.js
Here is a configuration you can use to post-filter the MathML to fix the invalid -italic math variant value.
MathJax = {
startup: {
ready() {
MathJax.startup.defaultReady();
MathJax.startup.input[0].postFilters.add(({data}) => {
data.walkTree(node => {
if (node.attributes) {
if (node.attributes.get('mathvariant') === '-italic') {
node.attributes.set('mathvariant', 'italic');
}
}
});
});
}
}
}
Place this in a <script> tag just before the script that loads mml-html.js.

Couls someone explain why i get this error? "TypeError: Cannot read property 'split' of undefined"

I'm new to Node js and i have a function that receives a json object with numeric values, that i try to add up and display the result on the browser using a "Sum" property. The problem occurs at the mathsServer.js (split() method in the addera()). I do not understand why i suddenly get this error especially when i modified my code according to a MVC. When i run it independently in one file it worked well at some point. Here is my code.
Im supposed to POST a json in postman:
{
"tal": "10,343,24,345,22,23,233, 45, 200,500"
}
router.js:
const express = require("express");
const router = express.Router();
const controller = require("./controllers/controller");
router.post("/add", controller.renderSum)
router.get("/add",controller.renderSum)
module.exports = router
controller.js:
const mathServerModel = require("../../../mathServer/model/mathModel");
exports.renderSum = (req, res) => {
mathServerModel.addera(req.body.tal)
.then(function (data) {
console.log(data);
//res.send({data});
res.render("post-tal", {
Sum: {data} // A property called Sum to be displayed on the browser
})
})
.catch(error => console.log(error))
}
mathModel.js
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
const addera = async (tal) => {
let strNumbersArr = tal.split(","); // ["10", "343", "24", ..., "233"]
let sum = 0;
for(let i = 0; i < strNumbersArr.length; i++) {
let currentNumberStr = strNumbersArr[i];
sum += Number(currentNumberStr); // convert current number string into a number
}
return sum;
}
module.exports = {
addera
}
index.hbs
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>WebApp</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.2/css/bulma.min.css">
<link rel="stylesheet" type="text/css" href="../css/style.css">
<style>
.eNavAction {cursor:pointer}
.buttons {margin-top: 20px}
</style>
<script src="js/simple-helper.js"></script>
<script src="model/customer-model.js"></script>
<script src="view/customer-view.js"></script>
<script src="controller/main-controller.js"></script>
<script>
var Current = {};
const Model = new TeamsModel();
const View = new TeamView();
const ViewTal = new TalView();
const Controller = new MainController();
document.addEventListener('DOMContentLoaded', function() {
// Controller.init();
Helper.onClassClick('eNavAction',Controller.navAction);
});
</script>
</head>
<body>
<nav class="navbar is-link" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<span style="font-weight:bold; font-size:20px" href="http://127.0.0.1:3000/">My Web App</span>
</a>
</div>
<div id="navbar" class="navbar-menu">
<div class="navbar-start">
<a class="eNavAction navbar-item" action ="teams" href="http://127.0.0.1:3000/">Teams</a>
<a class="navbar-item" action= "tal">Sum</a>
</div>
</div>
</nav>
<div class="section">
<div id="main-container">
<div class="enterTal">
<div class="displaySum">
<p>Sum is: {{Sum}}</p>
</div>
</div>
</div>
</div>
</body>
</html>
It appears in controller.js req.body doesn't have an object tal (req.body.tal). You must start your investigation there. mathServerModel.addera() call is passing Undefined object as parameter.
In mathsServer.js, make your code defensive, by first checking your parameters' validity. Check if they have the values and types you were expecting before going into your function's logic.

How to pass an array in hogan-express template engine

How do I pass an array like the below to a HTML page using hogan-express? I am trying but it doesn't seem to be working.
My code:
apiRouter.get('/myPosts', function(req, res, next){
userModel.findOne({'profileID':req.session.facebookProfileId}, function(err, userPosts) {
if(userPosts) {
res.render('myPosts', {title:siteName + ': My Posts', posts:userPosts.posts});
} else {
console.log('You do not have any posts');
}
})
})
By the way, the userPosts.posts looks like the below:
["123","124","125"]
myPosts.html page is as below:
<!doctype html>
<head>
<meta charset="UTF-8">
<title>{{title}}</title>
</head>
<body>
<p>Post 1</p>
<p>Post 2</p>
</body>
</html>
By the way, the {{title}} bit is coming through.
In short: you can't, at least not like that.
What you can do is iterate over the posts:
{{#posts}}
<p>Post 1</p>
{{/posts}}
However, that would leave you with the problem of the text content for each link ("Post 1"). To fix that, you need to process the array server-side, before you pass it to render.
For example:
res.render('myPosts', {
title : siteName + ': My Posts',
posts : userPosts.posts.map(function(postId, idx) {
return { postId : postId, postNum : 1 + idx };
})
});
And the template:
{{#posts}}
<p>Post {{postNum}}</p>
{{/posts}}
The rendered HTML will look like this:
<p>Post 1</p>
<p>Post 2</p>
<p>Post 3</p>

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

Writing to a particular div in node js

I have this simple file hello.html and looks like this.
<!DOCTYPE html>
<html>
<head>
<style>
p { background:yellow; }
</style>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
<div class="thediv">
</div>
</body>
</html>
I am using fs module to write to my file like this
var fs = require('fs');
var randomnumber = Math.floor((Math.random()*100393)+433334);
fs.createReadStream('test.txt').pipe(fs.createWriteStream(randomnumber+'.txt'));
fs.writeFile(randomnumber+".txt", "Lorem ipsum"+randomnumber, function(err) {
if(err) {
console.log(err);
} else {
console.log("The file was saved!");
}
});
console.log(randomnumber);
I want to write
<article>
<p> lorem ipsum </p>
</article>
to the div with the id thediv.Is the fs module used for this kind of thing or is there a module more suited for this task?.
I believe the only answer to get an HTML parser, parse the file into a DOM, make the adjustments and then save the DOM back to a file. Here's a question that answers where to find an HTML parser.

Resources