Change an forEach depending on the locale - javascript

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

Related

Better way to write multiple switch cases in multiple foreach methods?

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

How can I refactor my 'view' code to display items per year?

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

EJS failing to render template

I'm trying to render a template which includes this block of code:
<% if(type === 'Not Within Specifications'){ %>
<% if(Length !== undefined) { %><h5>Length: <%= Length %> </h5> <% } %>
<% if(Width !== undefined) { %><h5>Width: <%= Width %> </h5> <% } %>
<% if(thickness !== undefined) { %><h5>Thickness: <%= thickness %> </h5> <% } %>
<% } %>
However when the template attempts to render, it throws and error that a variable is "undefined" if one of the above variables is in fact undefined.
The point of the if statements catching undefined variables was to eliminate this error from happening, however it seems that the error is still being thrown even when i'm checking to see if the variable is undefined. Does anyone know why this might be? Thanks so much!
You need to use typeof:
<% if(type === 'Not Within Specifications'){ %>
<% if(typeof Length !== 'undefined') { %><h5>Length: <%= Length %> </h5> <% } %>
<% if(typeof Width !== 'undefined') { %><h5>Width: <%= Width %> </h5> <% } %>
<% if(typeof thickness !== 'undefined') { %><h5>Thickness: <%= thickness %> </h5> <% } %>
<% } %>
Also, see this related question: How would you check for undefined property in ejs for node.js?

Setting a variable when user selects from a dropdown

In my rails view, I have a dropdown menu of patients. When a user selects a patient, I want to set #patient to be Patient.find(id) where id a data attribute on the item the user selected.
How can I achieve this?
Action:
def options
#assessment = current_user.assessments.new
#patients = current_user.patients.sort_by{|e| e.first_name.downcase}
#patient = current_user.patients.new
#templates = Template.all
end
View:
<%= form_for #assessment, :method=>"get", :url => url_for(:action => 'new') do |f| %>
<%= f.select :patient_id, content_tag(:option,'select patient...',:value=>"")+content_tag(:option,'New Patient',:value=>"")+options_from_collection_for_select(#patients, 'id', 'full_name'), :class=>"form-control" %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<div class="row" id="assessment-type" style="display:none;">
// WANT TO SET #patient HERE TO WHATEVER THE USER SELECTED IN ABOVE SELECT TAG //
<% if #patient.has_past_assessments? %>
<%= link_to "New Injury", templates_path, :id=>"new-injury", :remote=> true %> or <%= link_to "Followup Assessment", "#" %>
<% end %>
<%= f.hidden_field :template_id %>
<% end %>
</div>
<script>
$(function(){
$('#assessment_patient_id').chosen({width: "100%"});
});
$('#assessment_patient_id').change(function(){
var e = document.getElementById("assessment_patient_id");
var patient_id = (e.options[e.selectedIndex].value)
if (patient_id == 0) {
window.location.href = "/patients/new"
} else {
$('#assessment-type').slideDown(350);
}
$('#assessment-type').find('.template').on('click', function(){
startSpinner()
var templateId = parseInt($(this).find('a').attr("id"));
$('#assessment-type').find('.template').removeClass('active');
$(this).addClass('active');
$('#assessment_template_id').val(templateId);
$('.new_assessment').submit();
});
});
</script>

how to expand and collapase list

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.

Categories

Resources