Using loops in backbone/underscore's templates - javascript

I have a backbone.js/underscore.js template that I am feeding into a backbone view for rendering. The View is passed a model that contains an array posts of objects (which I call post in the template).
Problem: When I try to loop through all the elements of the array posts, I get an error Uncaught SyntaxError: Unexpected token ) and refers a line in the backbone View's code template: _.template( $('#tpl_SetView').html() ).
Am I doing the loop incorrectly which is causing this error?
Template code
<script type="text/template" id="tpl_SetView">
<div class="row_4">
<div class="photo_container">
<div class="set_cover">
<img src="/<%= posts[0].thumb_subpath %><%= posts[0].img_filename %>" width=240 />
</div>
<div class="set_thumbs">
<%= _.each(posts, function(post) { %>
<img src="<%= post.thumb_subpath %><%= posts.img_filename %>" width=55 />
<%= }); %>
</div>
</div>
</div>
</script>

To echo a variable use <%= %>, but to parse javaScript code, just use <% %>.
For example:
// In your Backbone View
var posts = {"posts": this.model.toJSON()};
var template = _.template($("#tpl_SetView").html(), posts);
// In your template
<div class="row_4">
<div class="photo_container">
<div class="set_cover">
<img src="/<%= _.escape(posts[0].thumb_subpath) %><%= _.escape(posts[0].img_filename) %>" width=240 />
</div>
<div class="set_thumbs">
<% _.each(posts, function(post){ %>
<img src="<%= _.escape(post.thumb_subpath) %><%= _.escape(posts.img_filename) %>" width=55 />
<% }); %>
</div>
</div>
</div>

I think you will find that the problem is in these lines:
<%= _.each(posts, function(post) { %>
<img src="<%= post.thumb_subpath %><%= posts.img_filename %>" width=55 />
<%= }); %>
From my recollection of what underscore does to evaluate templates, these lines don't make much sense. Each <%=..%> item is evaluated separately.. that is, they must be full evaluatable expressions, not partial function blocks..
Edit: Actually, James is right. <%..%> can be defined separately (it all comes down to a big javascript string in the end). It is escaped and the interpolated expressions that must be separate expressions.
Edit II: Even so, in the evaluation context I think the use of the function block would still possibly create a bizzare javascript string that might not evaluate quite as intended... I'd have to think about it. It might still work out totally fine.

Related

forEach within ejs template is not defined

I have never used an ejs template before, and am relatively new to working with the front end.
My output is returning an object instead of an array, therefore I know forEach is not valid (currently getting an error that forEach is not defined, and that I should use for..in as an alternative.
Hoping someone can answer in what this would like using for..in
<% data.countries.forEach(function(country){ %>
<div class="card">
<div class="card-body">
<h3>Country Name: <img alt="" src="<%=country.icon %>" /> <%= Country.name %></h3>
<h5>Categories</h5>
<ul>
<% Country.categories.forEach(function(cat){ %>
<li><%= cat.name %></li>
<% }); %>
</ul>
</div>
</div>
<% }); %>

How to use a passed variable in an ejs file

SO i am trying to change the value of an html tag in an ejs file to a variable i declared in a JavaScript file
let checkbox = document.querySelector('input[name="plan"]');
checkbox.addEventListener('change', function () {
if (this.checked) {
document.querySelector('.plan-title').innerHTML = investment.name;
document.querySelector('.plan-description').innerHTML = investment.description;
}
else {
document.querySelector('.plan-title').innerHTML = '';
document.querySelector('.plan-description').innerHTML = '';
}
});
So when I pass it directly it shows but I want it to be dynamic and Although it gets pass through when i click the checkbox it doesn't seem to have any value.
<%- include('../partials/sidebar'); %>
<% if(currentUser && currentUser.isAdmin){ %>
Add New Plan
<% } %>
<div class="container">
<h1>Investments</h1>
<% investments.forEach((investment)=>{ %>
<div class="col-md-4">
<div class="card">
<strong>
<%= investment.name %>
</strong>
<h4>
<%= investment.min %> - <%=investment.max %>
</h4>
<p>
<%= investment.caption %>
</p>
<p><input type="checkbox" name="plan" id="">Choose investment</p>
</div>
<% if(currentUser && currentUser.isAdmin){ %>
Edit
Delete
<% } %>
</div>
<% }) %>
<% investments.forEach((investment)=>{ %>
<div class="">
<div><strong>Package: </strong>
<p class="plan-title">
</p>
</div>
<p class="plan-description">
</p>
<input type="number" name="" id="" min="<%= investment.min %>"
max="<%= investment.max %>">
</div>
<% }) %>
</div>
<%- include('../partials/footer'); %>
I cant seem to get through this, need help thanks!
If I got it right, you are trying to insert the value of the EJS variable in the HTML tag from JavaScript when the user clicks the checkbox.
The value of the HTML tag doesn't change because in your JS code:
document.querySelector('.plan-title').innerHTML = investment.name;
document.querySelector('.plan-description').innerHTML = investment.description;
investment.name and investment.description are undefined. Check the console on your page.
This is because you tried accessing EJS variables after the page finished rendering.
EJS is mainly used to pass server-side variables to the page before it is rendered. So once it's rendered you cannot access those variables.
So to have the values of those variables in your JavaScript after the page finishes rendering, try doing:
document.querySelector('.plan-title').innerHTML = '<%- investment.name %>';
document.querySelector('.plan-description').innerHTML = '<%- investment.description %>';
instead. This is how you pass the EJS variable to JavaScript. JavaScript now sees it as a string and there's no problem, unlike in your code where it was looking for investment object and returned undefined since that variable is not defined on the client-side.
Also, since you have a for-each loop in the HTML part, I'm assuming you are trying to change the values of specific plan-title and plan-description divs. If that's the case, '<%= investment.name %>' and '<%= investment.description %>' in JavaScript part should be in a for-each loop as well, but that would be a lot of mess.
I suggest you instead to right under the for-each loop in the HTML part, add class to the div tag according to the index of the for-each loop, add on change event to the checkbox, and pass the checkbox and the index of the for-each loop to the JavaScript function which would handle the on change event, include the EJS variables in the plan-title and plan-description divs, and in the JavaScript function that handles on change event change the CSS display property from display: none to display: block to these divs.
See an example:
HTML:
<% investments.forEach((investment, index)=>{ %>
<div class="col-md-4">
<div class="card">
<strong>
<%= investment.name %>
</strong>
<h4>
<%= investment.min %> - <%=investment.max %>
</h4>
<p>
<%= investment.caption %>
</p>
<p><input onchange="displayPlan(this, '<%= index %>')" type="checkbox" name="plan" id="">Choose investment</p>
</div>
<% if(currentUser && currentUser.isAdmin){ %>
Edit
Delete
<% } %>
</div>
<% }) %>
<% investments.forEach((investment, index)=>{ %>
<div class="plan <%= index %>" style="display: none;">
<div><strong>Package: </strong>
<p class="plan-title">
<%- investment.name %>
</p>
</div>
<p class="plan-description">
<%- investment.description %>
</p>
<input type="number" name="" id="" min="<%= investment.min %>"
max="<%= investment.max %>">
</div>
<% }) %>
JavaScript:
function displayPlan(checkbox, id){
if (checkbox.checked) {
document.querySelector(`.plan.${id}`).style.display = 'block';
}
else {
document.querySelector(`.plan.${id}`).style.display = 'none';
}
}
Cheers!
EDIT: Grammar and syntax issues
It's not clear to me what variable you're referring to, but any variable you set in a client-side script will not be available to you in an EJS file that you're rendering on the server. Server-side Node.js code and client-side JavaScript code have no knowledge of each other.

SyntaxError: Unexpected identifier in index.ejs while compiling ejs

<body>
<header>
<% include templates/header.ejs %>
</header>
<% include templates/announcement.ejs %>
<form>
<br><input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search a fort...">
</form><br>
<section id="placeList">
<div class="placeListBackground" id="placeListGet">
<ul id="placeCells">
<% placeData.forEach(function(placeData) { %>
<div class="placeContainer <%= placeData.category %>" class><img src= "<%= placeData.placeicon %>" alt="<%= placeData.placename %>" align="left" width="178" height="100"><span><%= placeData.placename %></span><p><%= placeData.clan %></p><p>Playing: <%= placeData.playing %></p><p class="sCategory"><%= placeData.category %></p></div>
<% }); %>
</ul>
</div>
</section>
<br><footer>Contact us: https://discord.gg/fMb5y7T</footer>
</body>
<% include templates/search.ejs %>
I've checked through and tested a bunch of different tags for ejs just in-case but I do not see why this is not working. It worked previously but there must be some issue I'm overlooking unless it is the fault of ejs?
I think the problem is with the ejs tags.
You have wrote:
<% include templates/file.ejs %>
And should be:
<%- include ("templates/file.ejs") %>
At least I had same problem and solved that way, I hope is usefull.
look for more info about ejs changes:
https://github.com/RyanZim/EJS-Lint
try downgrading or upgrading ejs package

Nested loops in underscore templates with backbone

I'm using underscore for backbone templating, and I have a collection of models I'm passing to my underscore templates. I'm trying to loop through a series of objects in the collections' models, and then loop through an array of objects within each model. I tried doing this:
<% _.each(filters, function(filter,i){ %>
<div class="filter <%= filter.get('title') %>" data-id="<%= i %>">
<div class="filter-options-container">
<% var filterOptions = filter.get('filter'); for(var filterOption in filterOptions) { %>
<%= filterOption.id %>
<% } %>
</div>
</div>
<% }); %>
But of course that's not right. I'm just not sure how to get a collection's model attribute, and then get that attribute's array. Here's my data structure:
Where that second filters array is the nested loop I'm trying to go through. Any idea how to write this out? Also tried nesting each statements:
<% _.each(filter.get('filter'), function(filterOption,i){ %>
<%= i %>
<% }); %>
if i undestand you right, then:
you shouldn't sent to view backbone models as is, you should send them as toJSON().
for example:
_.template(tmpl_string)({filters : yourCollection.toJSON()});
template example:
<% _.each(filters, function(filter,i){ %>
<div class="filter <%= filter.title %>" data-id="<%= i %>">
<div class="filter-options-container">
<%= _.pluck(filter.filters, 'id').join(', ') %>
</div>
</div>
<% }); %>

Ajax request is not working in ruby on rails

i created a quiz and question displayed one by one and have to display the questions in list where it click it goes to the id of the question in list. but it does not work it the loader does not stops
here is my script
<script type="text/javascript">
function set_active(){
$$('.active-link').each(function(e){
e.removeClassName('active-link');
});
this.addClassName('active-link')
}
function draw_report(){
Element.show('loader')
new Ajax.Request('answers/ans',
{asynchronous:true, evalScripts:true,
parameters:'passed_question='+this.id+'&exam_group_id=<%= #exam_group.id %>',onSuccess:function(request){Element.hide('loader')}
})
}
document.observe("dom:loaded", function() {
$$('.student-link').invoke('observe','click',draw_report);
$$('.student-link').invoke('observe','click',set_active);
});
</script>
in the view page
<div class="list_id">
<%= "Questions" %>
</div>
<% #slno = 0 %>
<ul class="student_list">
<% #questions.each do |s| %>
<% #slno = #slno+1 %>
<li class="student_names">
<a href="#" id="<%=s.id%>" class="student-link" > <%= #slno %></a>
</li>
<% end %>
</ul>
but if i click the question id it does not respond anything
Are you getting no errors at all from the Javascript console you're using? I'd say adding parentheses should do the trick:
$$('.student-link').invoke('observe','click',draw_report());
$$('.student-link').invoke('observe','click',set_active());
EDIT: I see you use a jQuery tag in your original question. Are you sure you're using jQuery? Because the javascript code above looks suspiciously like Prototype.

Categories

Resources