Nested loops in underscore templates with backbone - javascript

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>
<% }); %>

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 check policies for objects created through AJAX

In my program one Board can have many Sections. On Boards#show I list all Sections for this Board. A user can create, edit and delete Sections for Boards this user has created.
I use Pundit for my authorizations.
My problem is that after having added AJAX to the create Section action, my policy checks don't work anymore. The AJAX call is working fine in that Sections are added but the "Edit" and "Delete" links are only displayed after I reload the page.
Boards#show
<% if policy(#board).edit? %>
<p><strong>Create a new Section</strong></p>
<%= render 'sections/shared/form', board: #board, section: #section %>
<% end %>
<br>
<p><strong>Sections</strong></p>
<div id="sections">
<% #board.sections.order(id: :asc).each_with_index do |section, index| %>
<span><%= "#{index + 1}. #{section.title}" %></span>
<% if policy(section).edit? %>
<%= link_to "Edit", edit_board_section_path(#board, #board.sections[index]) %>
<% end %>
<% if policy(section).destroy? %>
<%= link_to("Delete", board_section_path(#board, #board.sections[index]), method: :delete) %>
<% end %>
<br>
<% end %>
</div>
Form partial
<%= simple_form_for([#board, #section], remote: true, authenticity_token: true) do |f| %>
<%= f.input :title, id: "section_title" %>
<%= f.submit "Save" %>
<% end %>
AJAX call
var newSection = "<span><%= "#{#board.sections.length}. #{#section.title}" %></span><br>";
var sections = document.getElementById('sections');
sections.insertAdjacentHTML('beforeend', newSection);
var sectionTitle = document.getElementById('section_title');
sectionTitle.value = '';
I think the problem is that the newly created Section isn't inserted into the loop and thus the policy cannot be checked. How could I refactor my code to solve this?
You should be able to render you HTML templates into your js.erb file. See the post from the DHH https://signalvnoise.com/posts/3697-server-generated-javascript-responses how to use this properly. It is an older post so maybe some things changed but you should know what to search for. But if it still works this way, you should be able to do something like this:
Extract section to a partial _section.html.erb
<span><%= "#{index + 1}. #{section.title}" %></span>
<% if policy(section).edit? %>
<%= link_to "Edit", edit_board_section_path(#board, #board.sections[index]) %>
<% end %>
<% if policy(section).destroy? %>
<%= link_to("Delete", board_section_path(#board, #board.sections[index]), method: :delete) %>
<% end %>
<br>
Use this partial also in your Boards#show file.
Render your partial in the js.erb file
var newSection = "<span><%=j render #section %></span><br>";
Something like this should work, but I don't use server generated javascripts so they could have changed some things. But hopefully it will help you at least with the direction.

Passing specific data on partials using Ajax in Rails

I'm new to rails and what I'm trying to do is the following:
I'm creating a store and unstore button to save and 'un-save' the event respectively. I used my event attributes and current user to find that stored event. By using ajax and remote functionality of rails I will able to change the behavior of the button from store to unstore or vise versa.
In my _feed.html.erb.
<% if #feed_items.any? %>
<ul>
<%= render partial: 'shared/feed_item', collection: #feed_items %>
</ul>
<% end %>
Each #feed_items contains set of data (title, category, etc).
In my _feed_item.html.erb.
<li id="<%= feed_item.id %>" class="item">
...
<div class="small-3 text-center columns">
<%= render 'shared/store_form', event: feed_item %>
</div>
...
</li>
Event symbol sends that feed_item to the store_form.
In my _store_form.html.erb.
<div id="store_form_<%= event.id %>">
<% if event.stored?(current_user) %>
<%= render 'shared/unstore', event: event %>
<% else %>
<%= render 'shared/store', event: event %>
<% end %>
</div>
I pass again a feed_item into partial.
_store.html.erb
<%= form_for(event.storages.build(saver_id: current_user.id,
organizer_id: event.user_id),
remote: true) do |f| %>
<div>
<%= f.hidden_field :organizer_id %>
<%= f.hidden_field :saved_id, value: event.id %>
</div>
<%= f.submit "store" %>
<% end %>
_unstore.html.erb
<%= form_for(event.storages.find_by(saver_id: current_user.id,
organizer_id: event.user_id) ,
html: { method: :delete },
remote: true) do |f| %>
<%= f.submit 'unstore' %>
<% end %>
create.js.erb
$("#store_form").html("<%= escape_javascript(render 'shared/store', event: event )%>")
destroy.js.erb
$("#store_form").html("<%= escape_javascript(render 'shared/unstore', event: event) %>")
And I'm getting these errors when clicking store/unstore event.
ActionView::Template::Error (undefined local variable or method `event' for #<#<Class:0x00000004d69be8>:0x00000004d68d10>):
1: $("#store_form").html("<%= escape_javascript(render 'shared/unstore', event: event) %>")
ActionView::Template::Error (undefined local variable or method `event' for #<#<Class:0x00000004d69be8>:0x00000004fdc6a0>):
1: $("#store_form").html("<%= escape_javascript(render 'shared/store', event: event )%>")
My question is, how can I pass that specific "event" data into the partial. I can't used #feed_item onto the create and destroy js because feed_item have the set of events. Is there any better approach to handle this?
In your action create and delete in the controller you should instantiate your variable event: change event by #event and change your js to:
$("#store_form").html("<%= escape_javascript(render 'shared/unstore') %>
because you donĀ“t need add instantiate vars to render calls, rails is doing for you

Change CSS for each item in Rails each method

So my each method works, but I am trying to add some code to make the dice change to its color that it is given. I am using rails and jquery/javascript. I just want to print the "dice type" and have it printed in the color it is given. Any thoughts?
Heres my original code:
<% #last_move.rolls.last.results.each do |dice| %>
<li>
<%= dice.type %> - <%= dice.color %>
</li>
<% end %>
And heres is my sorry failed attempt to make it just display the type with the color given:
<% #last_move.rolls.last.results.each do |dice| %>
<li>
<script>
$(this).css({ color: "<%= dice.color %>" });
</script>
<%= dice.type %>
</li>
<% end %>
I wouldn't use JavaScript for this, instead:
<% #last_move.rolls.last.results.each do |dice| %>
<li class="dice-<%= dice.color %>">
<%= dice.type %> - <%= dice.color %>
</li>
<% end %>
Then in your css:
.dice-red {
color: //red, etc.
}

Only show taxonomies that belong to the selected store model Ruby

When a store is selected I would only like to see the taxonomies that belong to the selected store. Does anyone have any idea how I might do this? Either with Ruby or Javascript
<h3>Stores Offered In</h3>
<ul class="multi-column-checkbox">
<% for store in Store.all %>
<li><%= check_box_tag "idea[store_ids][]", store.id,
#idea.stores.include?(store) %> <%= store.name %></li>
<% end %>
</ul>
<br />
<h3>Taxonomies Offered In</h3>
<% for store in Store.all %>
<% if store.has_taxonomies? %>
<ul class="multi-column-checkbox">
<h4><%= store.name %></h4>
<% for taxonomy in store.taxonomies %>
<li><%= check_box_tag "idea[taxonomy_ids][]",
taxonomy.id, #idea.taxonomies.include?(taxonomy) %> <%= taxonomy.name %></li>
<% end %>
</ul>
<% end %>
<% end %>
Ok -- lots going on here. First of all, I'm making the assumption that you're using rails 3 or rails 4
Also it looks like this is nested into the ideas model, which not taken into account here, you'll have to modify the code for that.
Firstly - Try not to make calls directly to a model in a view unless you absolutely have to, that should be done in your controller. Also, in your view make sure you have a binding element for taxonomies for the jquery call you'll make later.
your_main_view_referenced_in_your_question.html.erb
<h3>Stores Offered In</h3>
<ul class="multi-column-checkbox">
<%- #stores.each do |store| %>
<li>
<%= check_box_tag "store[ids]", store.id, false, :data => {:remote => true, :url => url_for( :action => 'get_taxonomies', :id => store.id ), :method => :put}, :class => 'input-large' %>
<%= store.name %>
</li>
<% end %>
</ul>
<br/>
<div id="taxonomies">
</div>
Next you need to create a controller action to respond to your ajax call.
stores_controller.rb
### Add an action to let you do an ajax call
def get_taxonomies
#store = Store.find params[:id]
end
Now you need to create a ujs file that is rendered from your controller action In my example I named the controller action get_taxonomies so by default the view rendered will be get_taxonimies.js.erb
get_taxonomies.js.erb
if ($(".store_" + <%= params[:id] %>).length) {
$(".store_" + <%= params[:id ] %>).remove();
} else {
$('#taxonomies').append("<%= escape_javascript(render(partial: '/stores/taxonomy', locals: {stores: #stores } )) %>");
}
if ($("[class^=store_]").length > 0) {
if ( $('#taxonomies').find('h3').length ) {
// do nothing - leave the h3 where it is
} else {
$('#taxonomies').prepend("<h3>Store Taxonomies</h3>");
}
} else {
$('#taxonomies').find("h3").remove();
}
Now while you could write all your html inline in the js file, it's kind of ugly and easier to edit it later if you put it in a partial - since the js.erb file is calling taxonomy, you'll need a partial with the same name
_taxonomy.html.erb
<div class="store_<%=#store.id%>">
<h4><%= #store.name %></h4>
<ul class="multi-column-checkbox">
<%- #store.taxonomies.each do |taxonomy| %>
<li>
<%= check_box_tag "[taxonomy_ids][]", taxonomy.id, false %>
<%= taxonomy.name %>
<% end %>
</li>
</ul>
</div>

Categories

Resources