use closure inside underscorejs template - javascript

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.

Related

How to Access Array Value in Underscores Template / CLNDR for Custom Event Class

Bit confused about this.
Trying to add a custom class for event days on the CLNDR underscores template.
Here's my underscores template excerpt:
<div class="days clearfix">
<% _.each(days, function(day) { %>
<%= console.log(day.events[0]) %>
<div class="<%= day.classes %>" id="<%= day.id %>"><span class="day-number"><%= day.day %></span></div>
<% }); %>
</div>
From console.log(day.events[0]) I'm getting back an array with these date values:
I've tried the obvious, day.events[0].type or <div class="<%= day.classes %> <%= day.events[0].type %>" to access the type property in this array, but always get this error mesage in the console: Uncaught TypeError: Cannot read property 'type' of undefined.
How can I access the type value in the console logged associative array and insert it into my template rendering the word "incoming" (the value of type in the array) along with <%= day.classes %> in my template?
Not the most elegant solution I'm sure but I got it working by using a _.each with an if statement to only bring back the first type value:
<% _.each(days, function(day) { %>
<div class="<%= day.classes %><% _.each(day.events, function(k, v) { %><% if (v == 0) { %> <%= k.type %><% } %><% }); %>"><span class="day-number"><%= day.day %></span></div>
<% }); %>
Seems to be working as intended.. I'm sure there is a better answer though if anyone is inclined to share. Also still confused as to why I cannot access the value directly using day.events[0].type -- that would be the most preferred I assume. An each loop seems to be a hackish work-around though.

Rails How to make a filter link

I am working on a faceted search in rails. It follows from my previous question: Rails: How to use facets with search results
What I am able to do is to use scopes to get all the facets with respect to the search results as shown in the figure:
What I am currently working on is use the facets texts as a link to add extra params to the search result we already got.
I have two questions in regard to this:
How to take existing search URL and add a link to add/merge params when a link is clicked. I am using params merge which is not working.
The code is as below.
<h3 style = "color:#7C064D; text-align: center;"><strong>CYLINDER</strong></h3>
<%- #listings_cylinder.each do |key, value| -%>
<h5 style = "color:#F00000; text-align: left;"><strong><%= link_to "#{key.upcase if key} (#{value})" , search_listings_path(params.merge(:cylinder => "#{key}")) %> </strong></h5>
<% end %>
How to use multiple filters at the same time. What I want is when a facet link is clicked, it should add a small filter link below the
sorting link in the pic. When a user wants to undo that facet filter
effect, he clicks the X on that small link and he gets to the search
query without the filter. The same what happens on hotels.com or
priceline.com as shown:
Note: I don't want to use solr/elaticsearch because it's not the best use case here. I want to learn it from scratch. I am already able to build facets texts with simple rails. With a little help, I will be able to do it.
Codes:
Scopes I am using:
scope :listing_search_cities, -> {group(:city).count}
scope :listing_search_body_type, -> {group(:bodytype).count}
scope :listing_search_states, -> {group(:state).count}
scope :listing_search_newused, -> {group(:NewUsed).count}
scope :listing_search_transmission, -> {group(:transmission).count}
scope :listing_search_cylinder, -> {group(:cylinder).count}
scope :listing_search_fuel, -> {group(:fuel).count}
scope :listing_search_drive, -> {group(:drive).count}
scope :listing_search_trim, -> {group(:trim).count}
scope :listing_search_color, -> {group(:color).count}
scope :listing_search_year, -> {group(:year).count}
scope :listing_search_interiorcolor, -> {group(:interiorcolor).count}
In the controller search action, I am using:
def search
#listings = Listing.search(params)
#listings_cities = #listings.listing_search_cities
#listings_bodytype = #listings.listing_search_body_type
#listings_states = #listings.listing_search_states
#listings_newused = #listings.listing_search_newused
#listings_cylinder = #listings.listing_search_cylinder
#listings_transmission = #listings.listing_search_transmission
#listings_drive = #listings.listing_search_drive
#listings_trim = #listings.listing_search_trim
#listings_fuel = #listings.listing_search_fuel
#listings_color = #listings.listing_search_color
#listings_interiorcolor = #listings.listing_search_interiorcolor
#listings_year = #listings.listing_search_year
end
In view, I am using iteration through the key values like this:
<%- #listings_cylinder.each do |key, value| -%>
<h5 style = "color:#F00000; text-align: left;"><strong><%= link_to "#{key.upcase if key} (#{value})" , search_listings_path(params.merge(:cylinder => "#{key}")) %> </strong></h5>
<% end %>
Not the solution, but some ideas (not tested):
Pass all filters to the search method in a hash in params (such as params[:filters]).
Define an instance variable with all the filters and load it in the search method in the controller.
Filter the listing based on filters.
def search
#current_filters = params[:filters]
#listings = Listing.all
#listings = #listings.where(:cylinder => #current_filters[:cylinder]) if #current_filters[:cylinder]
#listings = #listings.where(:fuel => #current_filters[:fuel]) if #current_filters[:fuel]
#etc
end
In the view:
<% #listings_cylinder.each do |key, value| %>
<h5><%= link_to "#{key.upcase if key} (#{value})", search_listings_path(filters: #current_filters.merge(:cylinder => "#{key}")) %>
</h5>
<% end %>
In the view, when showing current filters:
Applied filters:
<ul>
<% #current_filters.each do |key, value| %>
<li><%= link_to value, search_listings_path(filters: #current_filters.except(key)) %>
</li>
<% end %>
</ul>

Is there a way in Rails to implement an image_tag type mouseover for just text? JavaScript & CSS solutions not working

Basic Problem: I have a line of text, and on hover, I want that text to change to something else. Basic, right? What's tripping me up is that the text in question is stored in a hash in my controller, and I'm looping through it.
Here's a smaller version of my hash in my PagesController:
def team_list
return [ {
name: "Employee 1",
title: "Founder and CEO",
secret_title: "Something Funny",
image: "about-employee-color.jpg",
alt_image: "about-employee-alt.jpg"
},
{
name: "Employee 2",
title: "Not Founder and CEO",
secret_title: "Something Else Funny",
image: "about-employee2-color.jpg",
alt_image: "about-employee2-alt.jpg"
} ]
end
So then in my view (with #team defined as that hash in my PagesController), I'm looping through to create an About Page entry for each person.
<% #team.each do |member| %>
<div class="about-team">
<%= image_tag member[:image], :mouseover => member[:baby_pic] %>
<%= image_tag member[:baby_pic], :style => "display:none;" %>
<h2><%= member[:name] %></h2>
<h4><%= member[:title] %></h4>
<h4 style="display:none;"><%= member[:secret_title] %></h4>
</div>
<% end %>
And I'm trying to see if there's an easy solution just like my image_tag :mouseover to get my titles to change to secret_titles on hover. I tried CSS first, similar to this. But I can't just put that member variable into the CSS since it doesn't exist outside that loop. I imagine JavaScript would be the same way.
h4:hover { content:<%= member[:secret_title] %>; }
Anyway, what I'm hoping for is something like a text_tag that I haven't come across yet that has a similar :mouseover attribute as image_tag.
You can use a JQuery functionality to swap values that you store directly as attributes in the DOM element, which in this case will be the div with class about-team, without really changing rails controller.
Storing values:
<% #team.each do |member| %>
<div class="about-team" member-title="<%= member[:title] %>" secret-title="<%= member[:secret_title] %>">
<%= image_tag member[:image], :mouseover => member[:baby_pic] %>
<%= image_tag member[:baby_pic], :style => "display:none;" %>
<h2><%= member[:name] %></h2>
<h4><%= member[:title] %></h4>
</div>
<% end %>
Swaping values (JQuery defined once):
$('.about-team h4').hover(
function(){ //mouse enter
$(this).html($(this).parent().attr('secret-title'));
},
function(){ //mouse leave
$(this).html($(this).parent().attr('member-title'));
}
);
JQuery hover event as defined in API docs binds 2 handlers to the matched elements, so you can execute your swap logic when mouse is over and out as done in the code above.
JSFIDDLE: http://jsfiddle.net/VmqB7/4/

Loops in Mustache-Mode Underscore Templates

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/

How can I return javascript from a Ruby on Rails helper method?

I have a Note model, which can contain have either an image link attachment (linktype = "image" or some text (linktype = "text). When I display the notes, the method of display changes depending on the linktype. An example is:
<% #notes.each do |q| %>
<h2 class="title"><%= q.name %></h2>
<% if q.linktype == "other"%>
<script type="text/javascript">some javascript</script>
<% elsif q.linktype == "text"%>
<%= q.text %>
<% elsif q.linktype == "image"%>
<img src="<%= q.link %>" />
<% end %>
<% end %>
I have to display the notes in a few different views in my site, so rather than have to repeat the viewing code multiple times, I want to have it in one place and refer to it from different views.
My initial thought was to put the display code in a helper, something like this:
<% #notes.each do |q| %>
note_display(q.linktype, q.link)
<% end %>
But some of the displaying involves javascript (line 4 in first code block). Can I still use a helper method, even though I would need it to return javascript? If so, how do I do it? Thanks for reading.
There's nothing special about javascript, you can return it from helpers as you would return other html content. The only thing I would suggest is to use helpers for tags like
image_tag(q.link)
javascript_tag("some javascript")
content_tag("h2", q.name, :class => "title")
As far as ERB is concerned, JavaScript is just string content like anything else rendered by a template. So your helper method can just construct and return a string:
def note_display(note)
content = ''
content << content_tag('h2', h(note.name), :class => 'title')
if note.linktype == 'other'
content << javascript_tag("some javascript")
elsif note.linktype == 'text'
content << h(note.text)
elsif note.linktype == 'image'
content << image_tag(note.link)
end
content
end
You can use this helper method using:
<% #notes.each do |n| %>
<%= note_display(n) %>
<% end %>

Categories