Unable to run LOOPS within Javascript Ruby on Rails View - javascript

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

Related

Rails 5, simple javascript with form submit

I am hoping someone can help me here. Been at this for a few hours, but can't seem to figure out why my Javascript is not working on my simple form. I'm simply trying to display comments using the ajax call. I have gem 'jquery-rails', and required jquery, and jquery_ujs in my application.js file. Here's the code I have so far:
I have a Joy model that has_many comments.
<% #joys.each do |joy| %>
<ul id="comments-<%= joy.id %>">
<% joy.comments.where(void:'f').each do |comment| %>
<li><%= comment.body %></li>
<% end %>
</ul>
<%= form_with(model: [ joy.user, joy, joy.comments.build ], data:{ "js-comments-#{joy.id}" => true}) do |f| %>
<%= f.text_area :body, :class=>'form-control', :required=>'true' %>
<%= f.submit "Post Comment" %>
<% end %>
<script>
$(document).ready(function() {
$('[data-js-comments-<%= joy.id %>]').on("ajax:success", function(event, data, status, xhr){
$('#comments-<%=joy.id%>').append(xhr.responseText);
});
});
</script>
<% end %>
In my Comment controller, in my 'create' action, I have:
if #comment.save
render partial: "comment", locals: {comment: #comment}
end
In my Comment views, I created a partial, called _comment.html.erb:
<li>
<%= comment.body %>
</li>
So, now when I enter a comment, and click 'Post Comment', it correctly saves my Comment, but it does not ajax load the comment into list. Furthermore, the form does not refresh either. The text remains in the text box. It is not only until after I refresh the page when my comment shows up in the list. Anyone with any thoughts on what I'm missing or doing wrong???
Your help is greatly appreciated in advance.
form_with it's a remote form, you dont need that block <script>..</script>.
Just use create.js.erb then use jquery to append new comment.
And if you want to check if your message was created successfully, you can add a #status value in your controller.
//comments_controller.rb
def create
...
if #comment.save
#status = "success"
else
#status = "failed"
end
...
end
//create.js.erb - for example
$("#yourCommentList").append('<%= j( render partial: 'comments/comment', locals: #comment ) %>');
<% if #status == "success" %>
$("body").append(...your notification...)
...
<% else %>
...
<% end %>

How to break a loop with the EJS template language?

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

Show/hide of Form + Toggle link text; ActionView::Template::Error (undefined method `id' for nil:NilClass) - thinks model instance is nil?

I'm trying to toggle link text upon showing and hiding a form, but when I run the server I get a 500 internal server error. I'm trying to add a "solution" to an "aspect", and render the solution form with Jquery, toggling it when the link text changes from 'add solution' to 'cancel'.
Here is show.html.erb for an aspect:
<p>
<h1><%= #aspect.title %></h1>
<%= #aspect.brief %>
</p>
<% if #solutions.count > 0 %>
<h4>Solutions:</h4>
<p>Number of solutions: <%= #solutions.count %></p>
<ul class="media-list solutions">
<% vote_order(#solutions).each do |solution| %>
<%= render solution || "No solutions found" %>
<% end %>
</ul><!-- .solutions -->
<% else %>
<p class="no solutions">
This aspect does not yet have a solution. Why don't you describe one?
</p>
<ul class="media-list solutions">
</ul><!-- .solutions -->
<% end %>
<p class="solutions">
<%= link_to "Add solution", new_aspect_solution_path(aspect_id: #aspect.id, idea_id: #idea.id), remote:true %>
</p>
And new.js.erb for solution:
var selector = "ul.solutions"
if($("p.cancel").length == 0){
$(selector).append("<li class='js-inline-form'><%= j render :partial => 'solutions/form' %></li>")
$("p.solutions").replaceWith("<p class='cancel'><%= j link_to 'Add solution', new_aspect_solution_path(aspect_id: #aspect.id, idea_id: #idea.id), remote:true %></p>")
}
else if($("p.solutions").length == 0){
$(selector + " li.js-inline-form").remove()
$("p.cancel").replaceWith("<p class='answers'><%= j link_to 'Add solution', new_aspect_solution_path(aspect_id: #aspect.id, idea_id: #idea.id), remote:true %></p>")
}
And here is the error:
Completed 500 Internal Server Error in 25ms
ActionView::Template::Error (undefined method `id' for nil:NilClass):
1: var selector = "ul.solutions"
2: if($("p.cancel").length == 0){
3: $(selector).append("<li class='js-inline-form'><%= j render :partial => 'solutions/form' %></li>")
4: $("p.solutions").replaceWith("<p class='cancel'><%= j link_to 'Add solution', new_aspect_solution_path(aspect_id: #solution.aspect.id, idea_id: #solution.idea.id), remote:true %></p>")
5: }
6: else if($("p.solutions").length == 0){
7: $(selector + " li.js-inline-form").remove()
app/views/solutions/new.js.erb:4:in ` _app_views_solutions_new_js_erb___206213221362185261_2207575120'
app/controllers/solutions_controller.rb:15:in `new'
Don't really understand why it doesn't know what an id is when all I'm doing is creating a new tag with the exact same content, calling the exact same action. Thanks in advance for your help.
Update:
Also added
def set_aspect_idea
#aspect = Aspect.find(params[:id])
#idea = Idea.find(params[:id])
end
method to the solutions_controller, and set it before the :new action. I ran everything again and got this error:
ActiveRecord::RecordNotFound (Couldn't find Aspect without an ID):
app/controllers/solutions_controller.rb:90:in `set_aspect_idea'
I don't really understand what's going on.
Update 2
I changed new.js.erb to this:
var selector = "ul.solutions"
if ($(selector + ".js-inline-form").length == 0) {
$(".js-inline-form").remove()
$(selector)
.append("<li class='js-inline-form'><%= j render :partial => 'solutions/form' %></li>")
}
else {
$(".js-inline-form").remove()
}
And removed the set_aspect_idea from the controller and it works, but there is no toggling of the link text.
If I keep set_aspect_idea before the new action, I get thrown the same error as in update 1 above.
The problem is clearly in the replaceWith() part of the original new.js.erb file; even though the form is loaded onto an #aspect page, it thinks the #aspect is nil. Why is this?

Why does my js.erb file only run in one of these situations?

I have the following action on my controller for a Comment:
def create
#comment = comment.new(params[:comment])
#comment.replyable_type = params[:replyable_type]
#comment.replyable_id = params[:replyable_id]
#comment.user = current_user
respond_to do |format|
format.html do
# Removed
end
format.js do
#comment.save
end
end
end
and the following create.js.erb file for when it gets called by a remote form:
console.log('It did run');
<% if #comment.errors.any? %>
<% #comment.errors.full_messages.each do |msg| %>
console.log('<%= javascript_escape(msg) %>');
<% end %>
<% else %>
comment = "<%= escape_javascript render #comment %>";
<% if #comment.replyable_type == 'Comment' %>
$('#comment-<%= #comment.id %> > .replies').prepend(comment));
<% else %>
$('.comments').prepend(comment);
<% end %>
// removed
<% end %>
Along with the following form partial:
<%= form_for(Comment.new, url: comments_path, remote: true) do |f| %>
<div class="comment-form" id="comment-<%= replyable_type %>-<%= replyable_id %>">
<%= f.text_area :content, cols: 60, rows: 5 %>
<%= hidden_field_tag :replyable_id, replyable_id %>
<%= hidden_field_tag :replyable_type, replyable_type %>
<%= f.submit 'Send Comment', class: 'btn btn-primary' %>
</div>
<% end %>
replyable is a polymorphic association, which can be either a Post or a Comment object. When I submit a copy of the form on a page for a post, where replyable_type is Post and replyable_id is a post's ID, it works fine. When I submit a copy of the form on the same page, with the replyable_type set to Comment, and the replyable_id set to a comment's ID, the view the javascript does not run, at all. The action on the controller runs, using Firebug I can see the rendered javascript being sent back in response to the post request, and the comment is added to the database.
There are no errors in either the Rails console for generating the javascript or in the Firebug console to do with running the generated javascript. There are also no errors in the #comment.errors array. Even the first console.log in the Javascript is not run when the replyable object is a comment, despite being present in the rendered javascript.
What could cause this? I am using Rails 3.2.13 on Ruby 1.9.3

AJAX micropost's comments on the user page

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.

Categories

Resources