Optional include in ejs - node.js

Can I optionally include a partial if only it exists?
For example,
<%- include('some-template'); %>
should be complied to:
if some-template.ejs exists:
// content of some-template.ejs
if some-template.ejs does not exist:
// nothing
Currently, it throws an error if the partial not exists, like:
ENOENT: no such file or directory, open 'some-template'

Just enclose it with a if that checks the existence of the file:
<% if (fs.existsSync('views/some-template.ejs')) { %>
<%- include('some-template'); %>
<% } %>
Make sure your 'views' folder match the path inside the condition.
Also, you must send the fs object to the engine, so that it can be used in the scriptlet of the parent template:
res.render("main-template", {
fs: fs
});

Related

Unexpected token '/' in {FILE} while compiling ejs

I am working on this: https://www.youtube.com/watch?v=6FOq4cUdH8k
For some reason, the following line is causing the error in the title.
<% include ./partials/messages %>
Removing the line above solves the problem.
I have confirmed that it is not the messages file as there are no slashes in it.
<% if(typeof errors != 'undefined') { %>
<% errors.forEach(function(error){ %>
<%= error.msg %>
<% }); %>
<% } %>
as you can read in the official documentation
Includes are relative to the template with the include call. (This
requires the 'filename' option.) For example if you have
"./views/users.ejs" and "./views/user/show.ejs" you would use <%-
include('user/show'); %>.
You'll likely want to use the raw output tag (<%-) with your include
to avoid double-escaping the HTML output.
so instead of
<% include ./partials/messages %>
Write
<%- include ("./partials/messages") %>
Why?
Template tag <%- outputs the unescaped value into the template, whereas <% 'scriptlet' tag is used for control-flow, no output. The parenthesis and " " are used for filename location

How to place an EJS tag within another

I am using EJS as my templating engine. I am passing variables from node js to ejs like...
router.get("/AdminDatabase", function(req, res) {
res.render('Pages/AdminDatabase', {title: 'WebFormsAdmin', role: 'System Admin' });
});
I am building a role base control and for this I want to change the header of the page base on the role of user.
<% include ../partials/Common/header_<%= role %> %>
The problem is with the above segment. How can I place the variable role inside this EJS code segment?
My header files are
header_System Admin.ejs,
header_Survey Admin.ejs,
header_Survey Taker.ejs
A workaround would be to do a conditional render like so:
<% switch (role) {
case 'System Admin': %>
<% include ./partials/header_System_Admin %>
<% break; %>
<% case 'Survey Admin': %>
<% include ./partials/header_Survey_Admin %>
<% break; %>
<% default: %>
<% include ./partials/header_Survey_Taker %>
<% break; %>
<% } %>
Note that the first case must be grouped with the switch declaration. Make sure the paths are correct for your partials.
You can concatenate the path and the variable.
<%- include('../partials/Common/header_'+role) %>

What does file.path in gulp-exec mean

I have some questions about: https://www.npmjs.com/package/gulp-exec#usage
gulp.src('./**/**')
.pipe(exec('git checkout <%= file.path %> <%= options.customTemplatingThing %>', options))
.pipe(exec.reporter(reportOptions));
What do <%= => and file.path mean?
Do they come from node ? Could you give another example ?
Thank you
<%= =>
These are lodash.template "interpolate" delimiters. They allow you to insert arbitrary values into strings. You can provide those values in the second argument to exec(). Those values are then available as properties of the options object in the string. Everything from <%= to => is replaced with the value of the options property in between.
Example:
gulp.src('.')
.pipe(exec('cp <%= options.in %> <%= options.out %>', {in:'foo', out:'bar'}));
In the above:
<%= options.in %> is replaced with foo
<%= options.out %> is replaced with bar
So the command that gets executed is cp foo bar.
file.path
The options object is not the only object that is available for interpolation. The command in exec() is executed for each Vinyl file emitted from gulp.src(). Each time the command is executed the file object refers to the particular vinyl file that the command is executed on.
Example:
gulp.src(['foo.txt', 'bar.txt'])
.pipe(exec('rm <%= file.path %>', {}));
This executes two commands, one for each file matched by gulp.src():
rm /path/to/foo.txt
rm /path/to/bar.txt
It's showing the path for the files passing through the stream for the Gulp task, which is from Vinyl. Vinyl will have more information for what else you could use.
For example, you could get the filename by doing this instead
<%= file.relative %>

Add javascript code into the rails app

Actually, I'm having trouble adding javascript code into my rails application.
I tried putting the import.js in "app/assets/javascripts" as well and it didn't work either.
I also added, //= require import at the end of application.js file but still not working.As a result the whole application got stucked.
index.html.erb
TEST
<div id = "test">
<h2>Import Statements</h2>
<%= form_tag import_samples_path, multipart: true do %>
<%= file_field_tag :file %>
<%= submit_tag "Import" %>
<% end %>
</div>
sample.coffee
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
$( document ).ready(function() {
$("div#test").hide();
$("a").click(function(event) {
event.preventDefault();
$("div#test").toggle();
});
});
application.js
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require bootstrap-sprockets
//= require nicetitle
Thanks in advance.
A couple of things here:
First off - you need to have a //= require_tree . inside of your application.js file. What this does is automatically requires all of the files inside of your javascripts directory.
Next, (and I'm not entirely sure that this is best practice) the way that I call javascript inside of a html.erb file is inside of a <script> tag. I'll put an example of my code below. I only very recently figured out how to call JS from inside of html in rails, so like I said this is probably not best practice, but this is how I did it.
<script language="javascript" type="text/javascript">
var counts = ['Count']
var dates = ['x']
<% #chart.datasource.datapoints.each do |c| %>
dates.push( "<%= c.date %>" )
counts.push( <%= c.count %> )
<% end %>
chart(counts, dates);
</script>
So I actually put it inside of a script tag like you saw. Hopefully this helps.

Using interpolation within Node.js EJS includes

My Express app is using EJS, and my views directory looks like this:
./views
./contents
home.ejs
./includes
header.ejs
footer.ejs
layout.ejs
I'm trying to load home.ejs in my layout.ejs view conditionally based on a local variable named contents in my routes/index.js. That file looks like this:
/*
* GET home page.
*/
exports.index = function(req, res){
res.render('index', { title: 'Home', contents: 'home.ejs' });
};
Ideally I could simply write (in layout.ejs):
<% include '/contents' + contents %>
where the trailing "contents" is the local variable which contains the relative path to the body text to load.
But alas, it appears EJS always interprets the text following an include directive literally, and there is no chance for any interpolation magic to happen.
I've also tried to no avail:
<% function yieldContent(contents){ %>
<% var contentPath = 'contents/' + contents; %>
<% include contentPath %>
<% }; %>
<% loadContent(); %>
Does anyone have a creative solution for conditionally including a view based on a variable passed in routes?
I think there is no way to do this kind of dynamic includes in EJS. It might break the separation of business logic and view.
The solution can be to rendering the subtemplate in the controller, and passing its content to the layout.
For rendering subtemplate in the controller use something like this:
var ejs = require('ejs'),
, fs = require('fs')
, home = ejs.render(fs.readFileSync("contents/home.ejs", "utf-8"))
In the version 2 of EJS, the include function does it well. With it, includes are inserted at runtime so variables can be used as pathnames.
In this case, the solution may be :
<%- include('contents/' + contents) %>
The function can also have another argument if necessary :
<%- include('mypathname', {foo:"bar"}) %>
The pathname has to be relative to the template which calls the function.
Currently this hasn't been implemented into ejs but, there is this discussion and pull request that offers the functionality.
https://github.com/visionmedia/ejs/issues/93
in your render function you can include fs.readFileSync and __dirname.
Render your page with options like this
res.render('pages/'+req.file,{file_get_contents:fs.readFileSync,__dirname:__dirname});
Then you can use it in your .ejs page like this. This remains in server side.
<% var products=JSON.parse(file_get_contents(__dirname+'/web/data/products.json','utf8')) %>
You can print the data on client HTML like this.
<%- JSON.stringify(products)%>
Note : Using this method means you have fs included somewhere at the top of your script.
var fs = require('fs')

Resources