I am developping a simple web application with sails.js.
In my frontend code, i'm looping over an array of objects sent by the controller, and i am searching for a specific object. I'd like to break the loop once the object has been found. Is there a clean way to do that using the ejs template language ?
I coulnd't find anything about it on the EJS official website, nor on sails website.
I naively tried this until now :
<% objects.forEach(function(object) { %>
<% if(object.someId == someValue) {%>
<%= object.name %>
<% break %> <!-- This raise an illegal statement exception -->
<% } %>
<% } %>
The following code works as expected, but i'm looking for a cleaner solution if any
<% var found = false %>
<% objects.forEach(function(object) { %>
<% if(object.someId == someValue && !found) {%>
<%= object.name %>
<% found = true %>
<% } %>
<% } %>
It's not an EJS-related question.
break statement terminates the current loop. While you are not inside a loop. You are inside callback function, that's called by forEach method once per array element. There's no ability to interrupt forEach (see How to short circuit Array.forEach like calling break?). But, if you need it, you may use for loop for a clean solution:
<% for (var l = objects.length, i = 0; i < l; i++) { %>
<% object = objects[i]%>
<% if(object.someId == someValue) {%>
<%= object.name %>
<% break %> <!-- This will work as expected -->
<% } %>
<% } %>
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
}
})
}
I want to perform a check to provide instant validation feedback on the input of a field in my bootstrap form for my Profiles model using java/coffee-script. My current solution is working but feels rather clunky and I would like to improve it.
Here are some code examples of what I'm doing.
app/views/profiles/_form:
<%= bootstrap_form_for(#profile, layout: :horizontal, html: {id: "profile-form"} ) do |f| %>
<%= f.text_field :name %>
<%= f.text_field :number, id: "number-field" %> //Field to check
<%= form_group do %>
<%= f.primary %>
<% end %>
<% end %>
app/assets/javascript/profile_number_control.coffee:
$(document).on 'ready page:load', ->
$field = $("#number-field")
$group = document.getElementById("profile-form").childNodes[5]
numberPattern = "^(19|20)[0-9]{6}-[0-9]{4}$"
$helpBlock = $group.getElementsByClassName("help-block")[0]
$field.keyup ->
//This works fine, just wanted to show what is going on
if inputIsValid()
set $group class to " has-success"
set $helpBlock message to successful
else
set $group class to " has-error"
set $helpBlock message to corresponding error message
Here is the problem. I want this script to work for both profile#new and profile#edit, but since the array of elements given by document.getElementById("profile-form").childNodes differs in length depending of the current view I can not use the same index (5 in the example) for both #new and #update.
Does anyone know how to set an id to that specific form_group in my view? Or do I have to actually write out the whole html code to be able to place an id there properly?
This might help !
<%= bootstrap_form_for(#profile, layout: :horizontal, html: {id: "profile-form"} ) do |f| %>
<%= f.text_field :name %>
<%= f.text_field :number, :input_html => { id: "number-field" } %> //Field to check
<%= form_group do %>
<%= f.primary %>
<% end %>
<% end %>
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?
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 %>");
On the user's page there are microposts and each of them have it's own comment form and comments. Using "Endless Page" railscast i'm trying to create "show more comments" button, which will load comments by AJAX. But it's not working.
The problem is in show.js.erb file because:
1) common pagination of comments (without AJAX) is working well
2) "show more button" is working well too. I tested it on the users list page
I think "show more comments" not working because it don'understand <%= j render(comments) %> , <%= j will_paginate(comments) %> and i should have here variables like <%= j render(#comments) %> , <%= j will_paginate(#comments) %>.
But when i try to write in my users_controller.rb
def show
#micropost = Micropost.find(params[:micropost_id])
#comments = #micropost.comments
end
it's not working because on my user's page there are many microposts and i have an error "Couldn't find micropost without an id". So in my microposts/_micropost.html.erb i had to use this
<% comments = micropost.comments.paginate(:per_page => 5, :page => params[:page]) %>
<%= render comments %>
Can anyone please help? How should i change my show.js.erb?
users/show.html.erb
<%= render #microposts %>
microposts/_micropost.html.erb
...
micropost's content
...
<%= render 'comments/form', micropost: micropost %>
<% comments = micropost.comments.paginate(:per_page => 5, :page => params[:page]) %>
<div class="commentaries">
<%= render comments %>
</div>
<div id="append_and_paginate">
<%= will_paginate comments, :class =>"pagination", :page_links => false %>
</div>
javascripts/users.js.coffee
jQuery ->
if $('.pagination').length
$('#append_and_paginate').prepend('<a id="append_more_results" href="javascript:void(0);">Show more</a>');
$('#append_more_results').click ->
url = $('.pagination .next_page').attr('href')
if url
$('.pagination').text('Fetching more...')
$.getScript(url)
users/show.js.erb
$('.commentaries').append('<%= j render(comments) %>');
<% if comments.next_page %>
$('.pagination').replaceWith('<%= j will_paginate(comments) %>');
<% else %>
$('.pagination').remove();
<% end %>
<% sleep 0.3 %>
Bennington, in users/show.html.erb you have
But #microposts is not defined in your controller. What I think you want is to define #microposts as all the microposts associated with what, a User?
If so, you'd want something like `#microposts = Micropost.where(:user_id => current_user.id) or something.