I'm using NodeJS, expressJS and ejs to load files. while rendering index.ejs app.get('/', function(req, res){ res.render('index');, it loaded perfectly but when I'm embedding navbar.ejs in index.ejs <% include(includes/navbar.ejs) %> it is loading fine (no error in console) but nothing is appearing on the page.
Folder managed:
project>app.js ,
project>pages>index.ejs ,
project>pages>includes>navbar.ejs
I believe you have a typo there in your syntax. You're missing the - in the include. It should rather be
<%- include('includes/navbar.ejs'); %>
Also note that the path should be in quotes.
Related
I cannot find a way to include external .js file to Node ejs template. I want to put logic and data into object in external .js file, include that file to index.ejs template and pull data from it.
I tried by inserting standard way
<script src="sample.js"></script>, and it doesn't work
Then I tried ejs specific keyword <% include partials/sample.js %> and this works only for adding partials (ejs code snippets).
I inserted .js file into static directory which is defined in executable server.js, no results again.
But interestingly, including css file into ejs template classic way works fine, for example
<link href="/assets/styles.css" rel="stylesheet" type="text/css" />
Workaround would be to include external ejs file where I would put logic and data inside <% %> tags, but this is obviously a patch and not a viable solution, because ejs is not a js file. Besides, it doesn't work.
I cannot find any solution on Internet. Any hint?
Thanks
You can't.
Note: You can only pass data from .ejs file to .js file but not the other way. It won't work because .ejs is rendered on the server side while .js runs on the client side.
I am assuming you are using EJS on server side
1) You can pass an ejs variable value to a Javascript variable
<% var test = 101; %> // variable created by ejs
<script>
var getTest = <%= test %>; //var test is now assigned to getTest which will only work on browsers
console.log(getTest); // successfully prints 101 on browser
</script>
2) You can't pass a js variable value to a ejs variable
Yes, you can't: if it is on server.
Why:
The EJS template will be rendered on the server before the js is started execution(it will start on browser), so there is no way going back to server and ask for some previous changes on the page which is already sent to the browser.
A workaround with Express:
myScripts.js
module.export = {
foo() {},
bar() {}
}
Then in your app.js
var myScripts = require('/path/to/myScripts');
res.render('template', {
utils: myScripts
}); // you forgot a ')' here
then in your template.ejs
// utils will act in global scope for this file
<%
utils.foo();
utils.bar();
%>
I believe you are using it contrary to the intent.
In a controller you can define external scripts and styles you want to include like so
res.render('page-one', {
title: 'Page One',
data: pageData,
libs: ['page-one', 'utils'],
styles: ['page-one']
});
In your static assets for your app you have a js folder and a css folder
|- static/
|- css/
|- fonts/
|- img/
|- js/
favicon.ico
|- templates/
In your js folder you place the file page-one.js and utils.js
In your css folder you place the file page-one.css
In the head section of your html in the ejs template
<!-- styles included on all pages -->
<link rel="stylesheet" href="/css/bootstrap.css">
<!-- styles specific to individual pages -->
<% if (typeof styles !== 'undefined') { %>
<% if (styles.length > 0) { %>
<% for (let style of styles) { %>
<link rel="stylesheet" href="/css/<%= style %>.css">
<% } %>
<% } %>
<% } %>
Typically it is best practice to include scripts at closing body tag so they don't block page render so before the closing body tag in your ejs file
<!-- scripts included on all pages -->
<script src='/js/libs/jquery.min.js' type='text/javascript'></script>
<!-- page specific scripts -->
<% if (typeof libs !== 'undefined') { %>
<% for (let lib of libs) { %>
<script src='/js/<%= lib %>.js' type='text/javascript'></script>
<% } %>
<% } %>
</body>
When your page renders it will render the script and CSS includes automatically
The if block is in case you don't define any includes in the controller.
In your Express application you define your static and external script includes like so
Remember up above we created js and css folders inside a directory named static
// Define static assets
app.use(express.static('static'));
// included on all pages
app.use('/js/libs', express.static(path.join(process.cwd(), 'node_modules/jquery/dist'), { maxAge: 31557600000 }));
Finally, if you absolutely must include JavaScript in your template like rendering JSON data, etc. using special ejs tag <%- %>
<% if (jsonData) { %>
<script id="jsonData">var jsonData=<%- JSON.stringify(jsonData) %>;</script>
<% } %>
I was able to do that by:
serving the Js folder/file in the node app entry file like so:
app.use(express.static(path.join(__dirname, 'views/js')));
Added DOM functions in a index.js file which is in views/js folder.
Added script tag that links to the index.js file before the end body tag of index.ejs file like so:
<script scr="index.js" type="text/javascript"></script>
Note that the src in the script tag does not have "./js/index.js". I actually don't know why it works that way (same with external css stylesheet).
You can achieve it by adding the code below:
app.use(express.static(path.join(__dirname,public)));
You have to add a directory named public (or whatever you are naming) in your project folder. In that folder you can add your external JS file.
NB: the expression path.join is used to make the directory public available/accessible when you call/initiate app from outside the project folder.
I need to pass an object inside an ejs include statement. I found a couple of questions on the same issue but I get a weird error when i do the following,
<div>
<%- include (folder/index , {"user": user}) %>
</div>
I get,
ENOENT: no such file or directory, open '/views/(folder/index.ejs'
Any idea why i get a enoent when i pass the object inline ?
if i simply do,
<%- include folder/index %>
this works
but i need to pass user object to index. is there a way to do this?
When you insert space after include, EJS will use include preprocessor directives (<% include folder/index %>); Although they are still supported, the new syntax is like the following:
<div>
<%- include('folder/index', {user: user}) %>
</div>
(See includes Documentation)
found a solution...
Yes. I missed the obvious.
var json_tmp = JSON.parse('<%- JSON.stringify(pass_object) %>');
I've been using the following code with success across my whole website, its just a variable that is passed to the EJS to load a header:
Node
res.render('main', {
header: 'header1.ejs'
});
EJS
<%- include(header) %>
Today I switched from using "bcrypt" to using "bcrypt-nodejs" and now EJS gives me the following error every time I try and open a page.
Error: ENOENT, no such file or directory 'C:\Users\user\Desktop\node\views( header).ejs'
It seems to have forgotten how to parse variables, but only when coupled with Include as other variables passed to EJS still work. Removing "bcrypt-nodejs" doesn't seem to have fixed the problem. Does anyone have any idea what I've done wrong?
Figured it out, has nothing to do with bcrypt. EJS has updateded, the proper syntax is now:
<% include header %>
In a Node.js Express application is there a way of minifying all Handlebars templates before they are sent to the renderer?
I considered creating an Express middleware that does the minification on the HTML response body - but I soon realised that this is highly ineffective since the minification would occur on every HTTP request.
There has to be a way of minifying .hbs templates and cache them server side?
You can minify on the fly but for performance reasons I would recommend you to minify the file with an external minifier beforehand and therefore you just do it once. Otherwise you have to minify the html every time the file is called upon.
Therefore, another solution is to use html-minifier from the command line, with the option
--ignore-custom-fragments "/{{[{]?(.*?)[}]?}}/"
This regex will ignore everything between {{ and }} and HTML-minify the rest.
Only add the next flag "--continue-on-parse-error", the following command worked for me:
html-minifier --input-dir [SOURCE_DIR] --output-dir [TARGET_DIR] --file-ext hbs --collapse-whitespace --continue-on-parse-error --remove-comments --minify-css true --minify-js true
This did the trick:
https://github.com/helpers/handlebars-helper-minify
Only tiny issue is that you'd have to manually include the helper in every single template:
From the module's Github page:
{{#minify removeComments="true"}}
{{> header }}
{{/minify}}
{{#minify removeEmptyElements="true"}}
{{> body }}
{{/minify}}
{{#minify removeComments="true"}}
{{> footer }}
{{/minify}}
I had a problem include ejs into requirejs. I put <script data-main="js/app" src="js/require.js"></script> in my and inside of body create EJS object.
In my app.js,
require.config({
paths: {
//library
jquery: 'lib/jquery-1.11.1.min',
jquerymobile: "lib/jquery.mobile-1.4.2.min",
text: 'text',
ejs: 'ejs_0.9_alpha_1_production'
},
shim: {
"ejs": {
exports: 'ejs'
}
}
});
require(['jquery', 'jquerymobile','text','ejs'], function ($, mobile) {
console.log('jQuery version:', $.fn.jquery); // 1.9.0
});
when it is running, it throws EJS is not defined error. However, if I include
<script type="text/javascript" src="js/ejs_0.9_alpha_1_production.js"></script>
in the head, everything goes well.
Regards
Hammer
Lately I just get through similar trouble using ejs from the browser. I post the answer as it could save somebody's time.
I suggest you double check your ejs library is indeed coming from https://github.com/visionmedia/ejs. There is quite some tuned version of ejs around right now because it is becoming very popular. Unfortunatly most of thoses versions target specific needs and return different object to the window (eg. EJS instead of ejs) or don't even return anything usefull for requirejs.
=> In both case this would expalin why your shim exports return undefined.
Once you get it to load properly, let me also spot on an awesome requirejs-ejs plugin at https://github.com/whitcomb/requirejs-ejs . It could help you preload and render your template in a nice requirejs way.