Loops in Mustache-Mode Underscore Templates - javascript

I've set underscore to mustache mode like so:
_.templateSettings = {
interpolate : /\{\{(.+?)\}\}/g
};
I've got part of a template with the following:
<script id="detail_view" type="text/template">
<% for(registration in REGISTRATION_NUMBERS){ %>
<tr>
<td>{{registration.TYPE}}</td>
<td>{{registration.VALUE}}</td>
</tr>
<% } %>
</script>
Which results in "registration not defined". Using this causes the entire section to be output in the template. What am i doing wrong?

You have two problems, one you know about and one that you don't.
The first problem is that you're replacing all three _.templateSettings when you only want to replace one of them. You want this:
_.templateSettings.interpolate = /\{\{(.+?)\}\}/g;
That will leave the evaluate and escape parts of _.templateSettings alone. What you're doing is the same as:
_.templateSettings = {
interpolate : /\{\{(.+?)\}\}/g,
evaluate : undefined,
escape : undefined
};
so you're ending up without an evaluate at all. BTW, you can look at the source property of a compiled template function to see the JavaScript that your template is compiled to, the JavaScript isn't that easy on the eyes but looking at it can help with this sort of problem.
The problem you don't know about is that a for...in loop is for iterating over the properties of an object, not the values in an array. This means that registration will be the strings '0', '1', ... inside your loop and that's not what you want. You'd need something like this in your template if REGISTRATION_NUMBERS is an array:
<% for(var i = 0; i < REGISTRATION_NUMBERS.length; ++i) { %>
<% var registration = REGISTRATION_NUMBERS[i]; %>
<tr>
<td>{{registration.TYPE}}</td>
<td>{{registration.VALUE}}</td>
</tr>
<% } %>
Or, since you have Underscore around anyway, you could use _.each:
<% _(REGISTRATION_NUMBERS).each(function(r) { %>
<tr>
<td>{{r.TYPE}}</td>
<td>{{r.VALUE}}</td>
</tr>
<% }) %>
Demo: http://jsfiddle.net/ambiguous/jfckA/

Related

Using RegExp and eval() to replace a value

I need to use RegExp to replace a string and eval() to execute the object.
In my code below, I'm currently in a forEach of items.
item.url : http://localhost:3000/formation/[[item.id]]/[[item.launch_url]]
My code :
<% _.forEach(items, function(item) { %>
<% _.forEach(tableLineActions, function(tableLineAction) { %>
<% if (tableLineAction.conditionToShow) { %>
<% var label = tableLineAction.label; %>
<% var url = tableLineAction.url.replace(/\[\[item.id\]\]/g, item.id).replace('[[modelName]]', modelName).replace('[[item.seo_url]]', item.seo_url); %> // not reusable code
<% url = eval(url.replace(/\[\[/g, '').replace(/\]\]/g, '')); %> // test of a reusable code
<li><icon class="material-icons"><%=tableLineAction.icon%></icon><%=label%></li>
<% } %>
<% }); %>
<% }); %>
Error message : Invalid regular expression flags
I found a solution but this one is not maintenable if I want to send severals properties :
url = url.replace(/\[\[item.id\]\]/g, item.id).replace(/\[\[item.launch_url\]\]/g, item.launch_url)
With this solution, I need to add a new replace() method when a new property is sending and I want something more reusable without specifying all properties to replace.

Javascript map from java map

I want to create a javascript map from a java map to set a dropdown value depending upon the value selected in another dropdown.
Below is the code(not working):
var categoryAndReportsMap = new Object();
<%
Map<String,Set<String>> categoryAndReportsJ = (Map<String,Set<String>>) request.getAttribute("categoryAndReports");
for(Map.Entry<String,Set<String>> e : categoryAndReportsJ.entrySet()){ %>
categoryAndReportsMap[ <% e.getKey(); %> ] = <% e.getValue(); %>;
<% } %>
Please suggest how can I achieve this.
You need quotes around the keys and values :
categoryAndReportsMap["<%= e.getKey() %>"] = "<%= e.getValue() %>";
But this supposes those strings don't contain quotes themselves. The best solution would be to use a JSON serializer like the excellent gson, this would be as simple as
var categoryAndReportsMap = <%= gson.toJson(categoryAndReportsJ) %>;

use closure inside underscorejs template

Just wondering if there is any value in using a closure in an underscore template...say to keep track of counters or something. Here's a trivial example of what I mean:
<%
(function( models ){
var length = models.length-1,
section = "";
_.each( models, function ( item, index ) {
if (index === 0) {
section = "top";
} else if (index === length) {
section = "bottom";
} else {
section = "center";
}
%>
<div class="container">
<div class="gradiantDiv <%= section %>content">
<a href="/#customer/<%= item._id %>">
<address>
<strong><%= item.name %></strong><br>
<%= item.addr1 %><br>
<%= item.city %>, <%= item.state %> <%= item.zip %><br>
<abbr title="Phone">P:</abbr> <%= item.phone %>
</address>
</a>
</div>
<div class="gradiantDiv <%= section %>action">
<i class="icon-chevron-right"></i>
</div>
</div>
<%
});
})( models );
%>
Or is it just better to declare variables like "length" and "section" without a closure before the _.each? OR does it matter at all?
Thanks!
I don't personally know of any advantage to creating variables that wouldn't otherwise make sense outside of a template.
We normally create variables when they optimize or make code more readable.
(e.g.
length is only used once. I think its more readable and less work to use it in place. I've been rightly scolded during peer checkin reviews for creating variables just for the sake of some perceived legibility.
section is used many times and requires additional logic so it makes a lot of sense.
models doesn't do anything except force the interpreter to create a new pointer, why pass it in when it's available in a containing scope?
)
If it makes code more legible, or optimizes something then I'd say it's worth it.

Using jQuery UI autocomplete plugin in Rails app

I'm interested in using the jQuery UI autocomplete plugin in my Rails app. The number of possible values will be small, so I wanted to store them client-side. So I have my controller set up as follows:
def index
#tags = Tag.find(:all).map { |t| t.name }
end
And in my view:
var tags = <%= #tags %>
The problem is that this renders as:
var tags = ["tag1","tag2"];
Instead of:
var tags = ["tag1","tag2"]
What do I need to do differently in order to stop escaping those quotes inside my tag array?
What about:
var tags = <%=raw #tags %>;
EDIT:
in your controller
#tags = Tag.find(:all).map(&:name).to_json
in your view:
var tags = <%= #tags %>;
It's the same as what you presented but you're sure it's valid and sure (because escaped) json (+ the query is improved).
I'm still questioning about the XSS + raw...
I was able to solve this by changing my view code to:
<%= array_or_string_for_javascript(#tags) %>
The thing missing in your controller is html_safe - here is an example:
controller
#keys = #categories.map { |x| x.name }
#autocomplete_categories = #keys.to_json.html_safe
view:
<script type="text/javascript">
$(document).ready(function() {
var data = <%= #autocomplete_categories %>;
$("#auto").autocomplete( { source: data } );
});
</script>

javascript in my .html.erb using embedded ruby--escaping problems

I'm trying to embed data I have defined in my controller in my view.
in view.html.erb:
<script>
some_var = <%= #var_data %>
some_ints = <%= #int_data %>
</script>
in my controller:
#var_data = ['hi', 'bye']
#int_data = [1,2,3,4]
however, when I view the generated html file, it looks like
<script>
some_var = ["hi", "bye"]
some_ints = [1,2,3,4]
</script>
ie the ints are fine but all the quotes got escaped. I tried
some_var = <%= #var_data.map {|i| i.html_safe} %>
instead but it didn't do anything (and also html_safe didn't work on the whole array). How should I do this?
Thanks
have you tried this?
<%=raw #var_data %>

Categories