I'm trying to make a web app where people can add exercises to a routine for a certain day of the week, and it'll show their entire routine on one page. I also want the names of the exercises to link to their corresponding page. So for example, my data looks like this in mongodb:
_id:60e2edf7014df85fd8b6e073
routineName:"test"
routineUsername: "tester"
monday:[{
_id: 60e430d45395d73bf41c7be8
exercise: "Bicep curls"
}{
_id: 60e4329592e3fa445836d983
exercise: "Overhead press"
}]
tuesday:[{
_id:60e2ee8962c0c15840ecc69b
exercise:"Hanging leg raise"
}]
..etc
I have this in EJS:
<% routine.monday.forEach(monday => { %>
<ul>
<% switch (monday.exercise) {
case 'Hanging leg raise' : %>
<li><%= monday.exercise %></li>
<% break;
case 'Bicep curls' : %>
<li><%= monday.exercise %></li>
<% break;
case 'Calf raises' : %>
<li><%= monday.exercise %></li>
<% break;
case 'Barbell bench press' : %>
<li><%= monday.exercise %></li>
<% break;
case 'Incline bench press' : %>
<li><%= monday.exercise %></li>
<% break;
case 'Overhead press' : %>
<li><%= monday.exercise %></li>
<% break;
case 'Barbell squat' : %>
<li><%= monday.exercise %></li>
<% break;
case 'Shrugs' : %>
<li><%= monday.exercise %></li>
<% break;
} %>
</ul>
<% }) %>
..etc
But as you can see, I have to repeat this code 7 times for every day of the week, using switch case every single time just so I can get the exercises to go to their right links. I feel like this is a terrible and inefficient way to do this, but I don't know/can't think of better ways, any help would be appreciated.
A good practice is to use objects. You can call an object like foo.bar or foo['bar'].
So start by creating an object like:
const exercices = {
'Hanging leg raise': <li>
// Fill with the rest
...
}
routine.monday.forEach(monday => { %>
<ul>
exercices[monday.exercice]
</ul>
} %>
Use this design pattern has a base for what you need.
Or
routine.monday.forEach(monday => { %>
<ul>
<a href=`/muscles/abs/${monday.exercice.trim()}`><li><%= monday.exercise %></li></a>
</ul>
} %>
Related
I would like to refactor a piece of code in order to display / regroup my items per year without repeating the code for each of the years. As of now, I've tried looping through an array of years, but it didn't seem to work.
Here is the piece of code I'm currently repeating in a 'view' file (ejs template) for 8 different years :
<ul><h3>YEAR 2017:</h3>
<% items.forEach(function(el){ %>
<% if(el.date.substring(7, 11) == "2017"){ %>
<li><%= el.date %>:
<% if(el.url){ %>
<%= el.title %>,
<% }else{ %>
<%= el.title %>,
<% } %>
<% if(el.by){ %>
<%= el.type %>, <%= el.by %>
<% }else{ %>
<%= el.type %>
<% } %>
# <%= el.location %></li>
<% } %>
<% }); %>
</ul>
Seems like you are already on the right track by using an ejs template and using an array. Maybe you should restructure the way you are passing the items so that they are in an array of objects like so
items = [{"year": 2016, "items": [item1,item2...]},{"year":2017, "items": [item1,item2..]}, ... ]
Then you could loop through them in this way:
<% items.forEach(function(year){ %>
<ul><h3>YEAR <%= year.year %>:</h3>
<% year.items.forEach(function(el){ %>
...
<% } %>
<% } %>
maybe like this, please convert to eje syntax:
let arr = []
let arrEl = items.map(function(el, index){
return el.date.substring(7, 11);
})
arr.push(arrEl)
for (let i=0; i<arr.length; i++){
items.map(function(element, index){
if(el.date.substring(7, 11) == arr[i]){
//show your el
}
})
}
Executive Summary
Question 1: What is the value of providing local variables to a render, when they can access the instance objects in the controller?
Issue: I can NOT run a ruby loop within my _error.js.erb file. The goal of this loop is to provide DIRECT output to a $("#error_explanation") id regarding all of the
I was able to run the various other jquery commands as illustrated below.
I am able to run straight JQUERY commands leveraging ruby.
Dear Friends,
In my create controller, within it is the following:
format.js { render "_error.js.erb", locals: {post: #post, errors: #post.errors.messages} }
In my VIEW _error.js.erb, i have 3 JQUERY queries, two of them work, but the third does not work.
This Works. $("#error_explanation").append('<%= j pluralize(post.errors.count, "error") %> prohibited this secret from being saved: <p>');
This Works. $("#error_explanation").append('<%= post.errors.full_messages_for(:title) %>');
This Does NOT Work. $("#error_explanation").append('
<% post.errors.messages.each do |error| %>
<%= j error %>
<% end %>
I can only assume that it is because of my loop? Can I not perform loops in my javascript (js.erb) code?
Resulted in this Error
ActionView::Template::Error (undefined method `gsub' for ["Title can't be blank", "Subject can't be blank"]:Array):
5: <% end %>
6:
7: <% if post.errors.full_messages[1] %>
8: $("#error_explanation").append('<%= j(post.errors.full_messages.each {|n| n}) %>');
9: <% end %>
10: $("#error_explanation").css("color", "red");
Try with,
$("#error_explanation").append("<%= j(post.errors.full_messages.each{|msg| msg }) %>")
or
<%- str = "" %>
<% if post.errors %>
<% post.errors.full_messages.each do |error| %>
<% str+= error %>
<% end %>
<% end %>
$("#error_explanation").append("<%= j str %>");
<% if (locale === 'pt') {
data[i].info.pt.forEach(function(info) { %>
<li><%= info %></li>
<% }); %>
<% } else if (locale === 'en') {
data[i].info.en.forEach(function(info) { %>
<li><%= info %></li>
<% } else if (locale === 'es') {
data[i].info.es.forEach(function(info) { %>
<li><%= info %></li>
<% } %>
I have a variable called locale, which changes the value according to the language of the site, and I'm doing this forEach on an object, depending on the value of the locale, is there any way to make this better?
I was trying like this:
<% data[i].info. + locale + .forEach(function(info) { %>
<li><% info %></li>
<% }); %>
But it seems that I can not.
Use bracket notation:
<% data[i].info[locale].forEach(function(info) { %>
<li><% info %></li>
<% }); %>
The following is working fine. But its only working for the first instance of the revenue other instance are just showing the list without collapse or expand. As the user clicks on the revene.Amount it should expand and show revenue.Q1, revenue.Q2, revenue.Q3 and revenue.Q4. And by default everything should be collapsed.
<% #estate.revenues.each do |revenue| %>
<tr>
<td><%= revenue.Year %></td>
<div id="listContainer">
<ul id="expList">
<li>
<%= revenue.Amount %>
<ul>
<li><%= revenue.Q1 %></li>
<li><%= revenue.Q2 %></li>
<li><%= revenue.Q3 %></li>
<li><%= revenue.Q4 %></li>
</ul>
</li>
</ul>
</div>
<%= link_to 'Destroy', estate_revenue_path(#estate,revenue), method: :delete, data: { confirm: 'Are you sure?' } %>
<%= link_to 'Edit', edit_estate_revenue_path(#estate,revenue) %>
<%= link_to 'View', estate_revenue_path(#estate,revenue) %>
<br/>
</tr>
<% end %>
<br />
<%= link_to 'New Revenue', new_estate_revenue_path(#estate.id) %>
<script>
function prepareList() {
$('#expList').find('li:has(ul)')
.click( function(event) {
if (this == event.target) {
$(this).toggleClass('expanded');
$(this).children('ul').toggle('medium');
}
return false;
})
.addClass('collapsed')
.children('ul').hide();
};
$(document).ready( function() {
prepareList()
});
</script>
Your selector is likely the issue here. Furthermore, I feel you are trying to do too much with your chaining. Please try the refactored version of your code below:
$(function() {
var $list = $('#expList'),
$listItem = $list.find('ul li'),
$listItemChildren = $listItem.children('ul');
function prepareList() {
$listItemChildren.hide();
$listItem.addClass('collapsed');
$listItem.on('click', onListItemClick);
};
function onListItemClick(event) {
$this = $(this);
if (this == event.target) {
$this.toggleClass('expanded');
$this.children('ul').toggle('medium');
}
return false;
};
prepareList();
});
It is good practice to cache selectors like I have done in the first few lines of the closure. If you are still having problems, log $listItem and make sure that it contains an array containing the 4 list items you expect. If the selection is correct, add a log inside of the onListItemClick callback and log out what this is etc. etc.
In my messages board website I want to create a page and within all the forums arranged in alphabetical order. something like Wikipedia does.
it should be dynamic (forums can be created or deleted once in a while).
How do you do that?
Here's on controller :
#grouped = {}
Forum.all.each do |forum|
# take and capitalize first character from name
letter = forum.name.slice(0,1).upcase
#grouped[letter] ||= []
#grouped[letter] << forum
end
Here's on your view :
<ul>
<% #grouped.keys.sort.each do |letter| %>
<li>
<h2><%= letter %></h2>
<ul>
<% #grouped[letter].each do |forum| %>
<li><%= forum.name %></li>
<% end %>
</ul>
</li>
<% end %>
</ul>
Source
I hope this is helpful:
1.9.3p362 :002 > ["foo", "bar", "baz", "fuzz", "debian"].group_by {|x| x[0] }
=> {"f"=>["foo", "fuzz"], "b"=>["bar", "baz"], "d"=>["debian"]}