Use ejs template name inside template itself - javascript

I am using ejs templates to generate some contents inside different divs.
let's say it looks kind of like this:
<% include test1 %>
<% include test2 %>
<% include test3 %>
and in each of these templates, I would like to know what template I'm in automatically. for example, let's say I'm in "templatei.ejs" file (where i is the index of the ith template). now is there any way for me to know the template name inside it?
this is how each template file looks:
<div>
<h2>header info</h2>
<p>some text comes here</p>
<a href="/<% this.fileName() %>">now I want this url to be a link to a seperate page that only loads one template<a>
</div>
this.fileName() will not work it was just to express what I mean.
I actually want to add a link to a separate page for each of my divs.
the reason I don't use javascript to generate urls is that I want
crawlers to find it and I dont think a crawler would scrape the page
after js changes.

send the filename (which you want to render) in include statement.
<%- include('test1', {filename: 'data'}) %>
inside test1 ejs
<div>
<h2>header info</h2>
<p>some text comes here</p>
<a href="/<% filename %>"><a>
</div>

Related

How to render ejs variable as HTML using <script>

I'm making a simple blog project and I came up to this problem.
I'm using EJS and I'm trying to render variable as HTML using tag
What I tried:
<div class="container-fluid">
<script>
document.write(<%= content %>)
</script>
</div>
I thought this would work but it doesn't show
anything at all, if I type <p><%= content %></p> it shows it as words, not HTML.

Use ejs or header and footer templates for static hosting with github pages?

I have around 10 html documents that only differ due to one div. Is there any way to make a header and footer document, and link them together for each html document? I have used EJS in the past, so I would prefer using it. I am using github pages to host my site, so I cannot use any backend.
Yup! These are called partials in EJS, and you insert them with an include function:
<%- include('header') %>
<!-- Main content -->
<%- include('footer') %>
EJS will look for them in the local directory. Any parameters you passed into app.render in your Express route are passed down to partials too.
If you need to re-use partials on the same page with unique data, you can pass them a data object too:
<% msgs.forEach((msg) => { %>
<%- include('msgPartial', { msg: msg }) %>
<% }) %>

EJS partials/components

If I have the following directory structure, is it possible to be able to render partials within partials, basically like creating a view setup that is not to dissimilar to react components (that's how I see it anyway)
- server
- views
- partials
- components
component-1.ejs
component-2.ejs
blog.ejs
navbar.ejs
footer.ejs
home.ejs
contact.ejs
So within my home page I have a partial blog.ejs and within that partial I would like to have component-1.ejs
I have tried a variety of permutations but am always faced with the error Error: Could not find the include file
home.ejs
<div class="example">
<% include partials/blog %>
</div>
blog.ejs
<div class="another-example">
<% include components/component-1 %>
</div>
Is this kind of rendering possible with EJS ?

Interweave EJS and Javascript variables inside <% tags

I need to use a Javascript variable (defined in the front-end) in some EJS code, as follows:
var selected = 1;
<% for (var i=0; i < supplies.length; i++) { %>
if (i == selected) {
console.log(supplies);
}
<% } %>
I'm using EJS, Express.js and socket.io. I could convert the Javascript variable to an EJS variable by sending a message to my Node.js server instance, but that's kind of silly... Is there a way to use Javascript variables inside EJS?
EDIT:
I want to access supplies, a javascript array, after the user selected an item from a drop down menu. When he selects this item, a javascript function with the above code needs to access some EJS. That's why I need to use a normal Javascript variable in EJS.
Can I pass a JavaScript variable into a template?:
It is possible to get more data into the template and re-render it, but not in the manner that you're thinking, and without making another request to the server (unless it's to get more data, not to get more HTML).
Solution:
This question is going to be difficult to answer without more details, so I'm going to make some assumptions about why you want to pass a selected value into an EJS template. I'll do my best to answer this with limited information about your goals.
It seems like your user is performing some action on the page, like selecting a cleaning supply, and you want to render the data differently, based on which element the user selected. To do this, you can re-render the template and pass in data that identifies which element is selected, using a view helper to apply a specific class to the selected element:
Here is the modified cleaning.ejs template, with the class added using the view helper:
cleaning.ejs:
<script>
// NOTE: even if uncommented, JavaScript inside a template will not run.
// var selected = 1;
</script>
<h1><%= title %></h1>
<ul>
<% for(var i=0; i<supplies.length; i++) { %>
<li>
<!-- apply a class to the selected element -->
<a class='<%= supplies[i].selected %>' href='supplies/<%= supplies[i].value %>'>
<%= supplies[i].value %>
</a>
</li>
<% } %>
</ul>
The rendered HTML looks like this:
<script>
/** NOTE: Script blocks will not fire in rendered templates. They are ignored
// var selected = 1;
</script>
<h1>Cleaning Supplies</h1>
<ul>
<li>
<a class="" href="supplies/Broom">
Broom
</a>
</li>
<li>
<!-- Note the selected element -->
<a class="selected" href="supplies/mop">
mop
</a>
</li>
<li>
<a class="" href="supplies/Hammer">
Hammer
</a>
</li>
</ul>
This view was rendered using the following JavaScript code:
// modified data structure so that array of supplies contains objects
// with the name of the item and whether or not it's selected.
data = {
"title":"Cleaning Supplies",
"supplies":[
{
"value":"Broom",
"selected":""
},
{
"value":"mop",
"selected":"selected"
},
{
"value":"Hammer",
"selected":""
}
]
};
// pass data into template and render
var html = new EJS({url: 'cleaning.ejs'}).render(data);
// add HTML to the DOM using a <div id="container"></div> wrapper.
document.getElementById("container").innerHTML = html;
As you can see, supplies[i].selected applies the selected class to the element that was marked as selected in the data structure. I modified the href value so that it accessed the object in the ith array item instead of the value of the array itself.
Now, when the selected item is modified, we simply modify the data variable, re-render the EJS template, and add it to the DOM.
With this CSS in the head of your HTML document, you'll see something similar to what's displayed below:
<style>
.selected { color:red; }
</style>
Why JavaScript in the template doesn't run:
The method that you're attempting to use to manipulate JavaScript values or use JavaScript values inside the EJS template won't work. This has to do mainly with the context of when the JavaScript is executed.
You're right to think that the EJS templates are compiled on the client-side. However, the JavaScript in the view helpers are executed independent of the JavaScript in the Global context. From looking at the ejs.js source code, it appears as if eval is used in the process.
Additionally, EJS returns the rendered HTML as a string, and the documentation for EJS instructs us to inject that rendered template string into the DOM using innerHTML:
document.getElementById("container").innerHTML = html;
No matter what view technology you're using, one of the fundamental truths of some browsers when it comes to JavaScript is this: Some browsers may not evaluate <script> blocks added to the DOM using innerHTML.
In other words, in my test template, when I tried adding a script tag to output the selected value to the console, I could see that the script block was added, but due to the way innerHTML works, it was not executed:
Example Template Demonstrates JavaScript won't run if added using innerHTML:
<h1><%= title %></h1>
<ul>
<% for(var i=0; i<supplies.length; i++) { %>
<span id="selected"></span><script>console.info('test <%= i %> = <%= supplies[i] %>');</script>
<li>
<a href='supplies/<%= supplies[i] %>'>
<%= supplies[i] %>
</a>
</li>
<% } %>
</ul>
Rendered HTML:
As you can see below, the console.log statements are present in the HTML. However, when added using innerHTML, they will not fire.
The approach to take with view technologies is to limit their use to just that, rendering the view. Keep your logic in the "regular JavaScript".
<h1>Cleaning Supplies</h1>
<ul>
<span id="selected"></span><script>console.info('test 0 = Brrom');</script>
<li>
<a href='supplies/Brrom'>
Brrom
</a>
</li>
<span id="selected"></span><script>console.info('test 1 = mop');</script>
<li>
<a href='supplies/mop'>
mop
</a>
</li>
<span id="selected"></span><script>console.info('test 2 = Hammer');</script>
<li>
<a href='supplies/Hammer'>
Hammer
</a>
</li>
</ul>
More examples and documentation can be found on EJS Templates on the Google Code Embedded JavaScript site.

rendering a html.erb in rails with javascript

I create a page and some parts of it are layout files that are rendered. However I want to render one of these rendered part again with javascript code.
I want to render these part again
<div id="dialog" title="Bookmark Folders" style="resize: both;">
<%=render "layouts/filetree.html.erb"%>
</div>
It render function creates this:
<div id="accordion">
<% #user.folders.each do |f| %> <h3 id="<%= f.folder_name%>" class="folderBar"><b id="folderName"><%= f.folder_name%></b> created <%=distance_of_time_in_words(f.created_at, Time.now)%> before</h3>
<div class="<%= f.folder_name.delete(" ")%>">
<%if f.docs.empty?%>
<b>-No document currently!-</b>
<%else%>
<% f.docs.each do |r|%>
<%= r.title%><br/>
<b><%=r.url%></b><br />
<%= r.snippet%><hr/>
<%end%>
<%end%>
</div>
<%end%>
</div>
Because after some execution there are some changes over "folders", I want to render this part again to see the update.
You shouldn't attempt to render erb with javascript - it's not how it's done (not to mention you'd have to write yourself a erb parser and eventually call the server for data anyway).
If on the other hand, you're asking how to issue the render of some template using Javasript and then replace old content with new one then...
Watch this http://railscasts.com/episodes/205-unobtrusive-javascript,
read this Rails 3 and RJS to get the idea of how to trigger some content updates via javascript.
General idea is
Render the initial full page
Trigger ajax call (either after some time or by manual user request) to do a request to your rails application
Handle that request and respond to it with javascript script (the script content should contain all the functionality and content to replace what you want)
It's possible to share templates between the server and the client. One library that allows for this is called mustache.
But if this is the only case you need it I'd go with the RJS approach as well.
Instead of rendering I did it AJAX way and update it on the page. Thanks for the answers but I did not use any of these.

Categories

Resources