div_for

The anchor doesn’t get rendered I didn’t know what to use for the element name so I used the same as I used the same variable I passed to div_for in my view, commentable Thanks in advance

View:

<%= div_for(commentable) do %>

<% end %>

js.erb

$(document).on(‘turbolinks:load’, function(){

$(‘#commentable’).each(function(){

var elm = $(this);

elm.append(‘Comment’);

  });

});

There can only be one instance of an ID on any given page. And nothing you did in this example will render the id #commentable. If you look at my example, I did not use an ID on each element. The selector in $('#commentable').each should be $('#parent_of_the_list div'), and you'll have to apply whatever ID you want to search for to a parent element of the commentables. If you want to do this in a slightly simpler manner, you could apply a classname to the commentables, using the div_for helper: <%= div_for(commentable, class: 'commentable') do %>. Then you can change the jQuery to $('.commentable') and that will also work.

Walter

I’m render posts/index from a page called page.html.erb in the world controller and that in turn renders index action in posts controller and _index partial which in turn renders _post.html.erb The javascript anchor tag is in the top level view, page.html.erb The javascript has no effect on the html rendered No comment links displayed Thanks in advance

_post.html.erb

<%= div_for(post, class: ‘post’) do %>

<%= simple_format post.content %>

<% unless post.attachment.blank? %>

<%= image_tag(post.attachment, height: 250) %>

<% end %>

<%- end -%>

$(document).on(‘turbolinks:load’, function(){

$(‘#posts div’).each(function(){

var elm = $(this);

elm.append(‘Comment’);

});

});

Since I’m returning the new comment form shouldn’t it be rendered in a div that looks something like post_14_comment_5 or something

There can only be one instance of an ID on any given page. And nothing you did in this example will render the id #commentable. If you look at my example, I did not use an ID on each element. The selector in $(‘#commentable’).each should be $(‘#parent_of_the_list div’), and you’ll have to apply whatever ID you want to search for to a parent element of the commentables. If you want to do this in a slightly simpler manner, you could apply a classname to the commentables, using the div_for helper: <%= div_for(commentable, class: ‘commentable’) do %>. Then you can change the jQuery to $(‘.commentable’) and that will also work.

Walter

The anchor doesn’t get rendered I didn’t know what to use for the element name so I used the same as I used the same variable I passed to div_for in my view, commentable Thanks in advance

View:

<%= div_for(commentable) do %> <% end %>

js.erb

$(document).on(‘turbolinks:load’, function(){ $(‘#commentable’).each(function(){ var elm = $(this); elm.append(‘Comment’); }); });

This isn’t working I think since it’s a link in the view i should use $('#post div).click.(function(){ but this isn’t rendering anything The log shows the js file was rendered but nothing was added to the page

Here’s my page souce and js.erb it’s not appening anything to the page with the render

<div class="post">
  <p>Doing nothing as usual</p>
  <a data-remote="true" href="/comments/new?comment%5Bcommentable_id%5D=14&amp;comment%5Bcommentable_type%5D=Post">Comment</a>
</div>
<div class="post" id="post_14">
</div>

$(document).on('turbolinks:load', function(){
  $('#post div').click.(function(){
    var elm = $(this);
    elm.append('<%= form_for @comment do |f| %> <%= f.hidden_field :commentable_id, value: @comment.commentable_id %><%= f.hidden_field :commentable_type, value: @comment.commentable_type %> <div class="field form-group"> <%= f.text_area :body, class: 'form-control' %> </div> <div class="field form-group"> <%= submit_tag "Post comment", class: 'btn btn-primary' %> </div>	<% end %>');
  });
});

Show me the content_tag_for code you are using in your view. Copy and paste. The id that will be rendered depends on the instance variable that you send into the helper. It doesn't care about the surrounding page or the route that it took to render it.

If you pass in <%= content_tag_for :li, @foo do %> then you will get <li id="foo_124">, no matter on which page you put this. (The controller for that page must set @foo to be an ActiveRecord object, but that's the only expectation.)

Walter

You've skipped over the last set of instructions I sent you, and you really need to do this in order or it will never make sense. Show me the code you are using that loads the form into another page, and please don't post it unless it is working in a browser and you can save comments. Get that far, and THEN I will be happy to help you take it into Ajax land.

Walter

_post.html.erb

<%= content_tag_for(:div, post) do %> <%= simple_format post.content %> <% unless post.attachment.blank? %> <%= image_tag(post.attachment, height: 250) %>
<% end %> <%= link_to ‘Comment’, new_comment_path( ‘comment[commentable_type]’: ‘Post’, ‘comment[commentable_id]’: post.id), remote: true %> <%= content_tag_for(:div, post, :comment) do %> <% end %> <% end %>

produces

<div class="post" id="post_13">
	<p>listening to blues</p>
	<a data-remote="true" href="/comments/new?comment%5Bcommentable_id%5D=13&amp;comment%5Bcommentable_type%5D=Post">Comment</a>
	<div class="comment_post" id="comment_post_13">
</div></div><div class="post" id="post_14">
	<p>Doing nothing as usual</p>
	<a data-remote="true" href="/comments/new?comment%5Bcommentable_id%5D=14&amp;comment%5Bcommentable_type%5D=Post">Comment</a>
	<div class="comment_post" id="comment_post_14">
</div></div>

new.js.erb
  $('#post comment div)click.(function(){

This doesn't produce anything

> > > > There can only be one instance of an ID on any given page. And nothing you did in this example will render the id #commentable. If you look at my example, I did not use an ID on each element. The selector in $('#commentable').each should be $('#parent_of_the_list div'), and you'll have to apply whatever ID you want to search for to a parent element of the commentables. If you want to do this in a slightly simpler manner, you could apply a classname to the commentables, using the div_for helper: <%= div_for(commentable, class: 'commentable') do %>. Then you can change the jQuery to $('.commentable') and that will also work. > > Walter > > > > > The anchor doesn't get rendered I didn't know what to use for the element name so I used the same as I used the same variable I passed to div_for in my view, commentable Thanks in advance > > > > > > View: > > <%= div_for(commentable) do %> > > <% end %> > > > > js.erb > > $(document).on('turbolinks:load', function(){ > > $('#commentable').each(function(){ > > var elm = $(this); > > elm.append('<a href="/comments/new?commentable_id=' + elm.attr('id').split('_')[1] + '">Comment</a>'); > > }); > > }); > > > > > > > Here's my page souce and js.erb it's not appening anything to the page with the render > > <div class="post"> > <p>Doing nothing as usual</p> >
> > <a data-remote="true" href="/comments/new?comment%5Bcommentable_id%5D=14&amp;comment%5Bcommentable_type%5D=Post">Comment</a> > </div> > <div class="post" id="post_14"> > </div> > > $(document).on('turbolinks:load', function(){ > $('#post div').click.(function(){ > var elm = $(this); > elm.append('<%= form_for @comment do |f| %> <%= f.hidden_field :commentable_id, value: @comment.commentable_id %><%= f.hidden_field :commentable_type, value: @comment.commentable_type %> <div class="field form-group"> <%= f.text_area :body, class: 'form-control' %> </div> <div class="field form-group"> <%= submit_tag "Post comment", class: 'btn btn-primary' %> </div> <% end %>'); > }); > }); >

You've skipped over the last set of instructions I sent you, and you really need to do this in order or it will never make sense. Show me the code you are using that loads the form into another page, and please don't post it unless it is working in a browser and you can save comments. Get that far, and THEN I will be happy to help you take it into Ajax land.

Walter

_post.html.erb

<%= content_tag_for(:div, post) do %>     <%= simple_format post.content %>     <% unless post.attachment.blank? %>       <%= image_tag(post.attachment, height: 250) %><br>     <% end %>     <%= link_to 'Comment', new_comment_path( 'comment[commentable_type]': 'Post', 'comment[commentable_id]': post.id), remote: true %>     <%= content_tag_for(:div, post, :comment) do %>

You may want to insert the existing comments here:

<%= render post.comments %>

Then you can inject the form at the top or the bottom of the list. Remember, you'll need a _comment.html.erb partial in the views/comments folder for the short-hand to work.

    <% end %> <% end %>

produces

<div class="post" id="post_13">   <p>listening to blues</p>

  <a data-remote="true" href="/comments/new?comment%5Bcommentable_id%5D=13&amp;comment%5Bcommentable_type%5D=Post">Comment</a>   <div class="comment_post" id="comment_post_13"> </div></div><div class="post" id="post_14">   <p>Doing nothing as usual</p>

  <a data-remote="true" href="/comments/new?comment%5Bcommentable_id%5D=14&amp;comment%5Bcommentable_type%5D=Post">Comment</a>   <div class="comment_post" id="comment_post_14"> </div></div>

new.js.erb   $('#post comment div)click.(function(){

This doesn't produce anything

That's not surprising. Your RJS handler is going to be rendered with the same parameters that new.html.erb is when it creates a new page. So what you do in that instance is not observe a click (that click already happened) but rather identify the parts of the page that you want to replace, and replace them with the parts you need to insert. You're already on the other side of the click.

The content_tag_for method has a partner: dom_id(element, name_addition=nil). It produces just the ID for the element, not the entire element.

Inside the new.js.erb, rather than having the <%= render 'form' %> just spew out some HTML, you target where that should go:

$('#<%= dom_id(post, :comment) %>').prepend('<%=j render( 'comments/form' ) %>');

That will expand to $('#comment_post_14').prepend('<form ... >'); which will inject the form into the top of the comment_post_N container.

Trouble is, it will also do that again and again if you click the link repeatedly. To get around that, you could put the link to add a comment inside the container you want to fill with the form, and then use the jQuery html() method to replace the contents. That would look the same as above, just replace prepend with html. This gets around you needing to test if the form is already there, because the moment you click the link, the link is replaced with the form and you can't click it again.

So you have something like this in the end:

<%= content_tag_for(:div, post) do %>     <%= simple_format post.content %>     <% unless post.attachment.blank? %>       <%= image_tag(post.attachment, height: 250) %><br>     <% end %>     <%= content_tag_for(:div, post, :new_comment) do %>       <%= link_to 'Comment', new_comment_path( 'comment[commentable_type]': 'Post', 'comment[commentable_id]': post.id), remote: true %>     <% end %>     <%= content_tag_for(:div, post, :comments) do %>       <%= render post.comments %>     <% end %> <% end %>

The new.js.erb becomes this:

$('#<%= dom_id(post, :new_comment) %>').html('<%=j render( 'comments/form' ) %>');

And then to update the page, you want to render just that post again into the list. This is why you wanted to have the posts/index.html.erb depend on a _post.html.erb partial to render the list -- you're automatically set up to do this last step.

Make sure that your form_for method includes the remote: true configuration pair. This will submit the form via Ajax.

In comments_controller.rb, make sure you have a respond_to block for :js in the #create method. In case of an error, it will need to render the :new method again, but if the save succeeds, it should just render the create.js.erb by default (pass an empty block to that content_for).

create.js.erb would be something like this:

$('#<%= dom_id(@comment.post) %>').replaceWith('<%=j render @comment.post %>');

And that's really it. If it doesn't work, it's probably a typo on my part.

Walter

In _post.html.erb ?

This part would go into _post.html.erb

Walter

List comments and inject the form at the top or bottom of the list, what about a link to new comment we skipped over that no?

How do I give new.js.erb the right element name $('#comment_post)click.(function(){ In this line there’s no id number

I think you may have missed a few bits of my reply. We are not observing a click any more. Everything is out of the jQuery pool, and fully into the RJS pool. If you're viewing this in the Google Groups (Web) view, you may need to expand all of the little ... ellipses in order to see all of my threaded replies.

Walter

in the second content_tag_for statement collection: post.comments fails to produce anthing for comment.body when the _comment.html.erb partial is rendered

_post.erb.html

<%= content_tag_for(:div, post) do %> <%= simple_format post.content %> <% unless post.attachment.blank? %> <%= image_tag(post.attachment, height: 250) %>
<% end %> <%= content_tag_for(:div, post, ‘comments’) do %> <%= render ‘/comments/comment’, collection: post.comments %> <%= content_tag_for(:div, post, ‘comment_form_holder’) do %> <%= link_to ‘Comment’, new_comment_path(‘comment[commentable_id]’: post.id, ‘comment[commentable_type]’: ‘Post’) %>

<% end %> <% end %> <% end %>

_comment.html.erb

<%= content_tag_for(:div, @comments) do %> <%= simple_format comment.body %> <%= comment.post.user.first_name comment.post.user.last_name %> <% end %>

content_tag_for builds the DIV and gives it an ID based on a single item passed to it. I'm not sure what it would make of a collection of comments, which is what you're passing it here. What I think you need to do is change @comments to comment, to match the rest of the local variables inside the partial. @comments doesn't exist inside the partial unless you render it in a scope that already had that set as an instance variable. comment exists inside the partial because the partial is named comment, but that's only true if you are either rendering it with the "shortcut" collection: @comments, where @comments is an array or association of individual comment instances, or are rendering it one at a time, and passing in locals: { comment: @comment } or similar. Because you are doubly-nested at this point, inside _post.html.erb, it is best to stick with the local variables that you have passed along, and not rely on the surrounding render context to magically provide variables for you.

Try just changing @comments to comment in the first line of your _comment.html.erb, leave everything else alone, and see if it renders then. Just to be certain, check in the console whether you have any comments for that post you are trying to render. You should not see anything at all (the comment partial won't even render) if post.comments is empty.

Walter

I took out the div containers (content_tag_for) and just left: <%= simple_format comment.body %> <%= comment.post.user.first_name comment.post.user.last_name %> but I still get the error that comment is undefined

> > > > > > > > How do I give new.js.erb the right element name > > $('#comment_post)click.(function(){ > > In this line there's no id number > > I think you may have missed a few bits of my reply. We are not observing a click any more. Everything is out of the jQuery pool, and fully into the RJS pool. If you're viewing this in the Google Groups (Web) view, you may need to expand all of the little ... ellipses in order to see all of my threaded replies. > > in the second content_tag_for statement collection: post.comments fails to produce anthing for comment.body when the _comment.html.erb partial is rendered > > _post.erb.html > > <%= content_tag_for(:div, post) do %> > <%= simple_format post.content %> > <% unless post.attachment.blank? %> > <%= image_tag(post.attachment, height: 250) %><br> > <% end %> > <%= content_tag_for(:div, post, 'comments') do %> > <%= render '/comments/comment', collection: post.comments %> > <%= content_tag_for(:div, post, 'comment_form_holder') do %> > <%= link_to 'Comment', new_comment_path('comment[commentable_id]': post.id, 'comment[commentable_type]': 'Post') %><br><br> > <% end %> > <% end %> > <% end %> > > > _comment.html.erb > > <%= content_tag_for(:div, @comments) do %> > <%= simple_format comment.body %> > <%= comment.post.user.first_name comment.post.user.last_name %> > <% end %>

content_tag_for builds the DIV and gives it an ID based on a single item passed to it. I'm not sure what it would make of a collection of comments, which is what you're passing it here. What I think you need to do is change @comments to comment, to match the rest of the local variables inside the partial. @comments doesn't exist inside the partial unless you render it in a scope that already had that set as an instance variable. comment exists inside the partial because the partial is named comment, but that's only true if you are either rendering it with the "shortcut" collection: @comments, where @comments is an array or association of individual comment instances, or are rendering it one at a time, and passing in locals: { comment: @comment } or similar. Because you are doubly-nested at this point, inside _post.html.erb, it is best to stick with the local variables that you have passed along, and not rely on the surrounding render context to magically provide variables for you.

Try just changing @comments to comment in the first line of your _comment.html.erb, leave everything else alone, and see if it renders then. Just to be certain, check in the console whether you have any comments for that post you are trying to render. You should not see anything at all (the comment partial won't even render) if post.comments is empty.

Walter

I took out the div containers (content_tag_for) and just left:     <%= simple_format comment.body %>     <%= comment.post.user.first_name comment.post.user.last_name %> but I still get the error that comment is undefined

Where are you calling render on this template? Copy and paste the code here. Also copy and paste the error message so we can compare line numbers from the error with line numbers in your code.

Is the code that is quoted above exactly what you are using in your outer post partial? What should be happening if you call render 'comments/comment', collection: post.comments from inside the post.html.erb partial is that each of the post comments will be rendered one after another, and inside of each of those render calls, the instance variable 'comment' will be loaded with the one comment that is being rendered. This should Just Work™.

Walter

After some reading it occurred to me explicitly calling the comment partial with <%= render “comments/comment”, collection: post.comments %> was defeating the convention for the variable as partial name so I replaced it with <%= render @comments %> and then it worked Of course I had to set @comments=post.comments first on the preceeding line I’d like to know how I could have gotten it working without treating @comments as a standalone resource (in the context of rendering partials) like that