Search code examples
jqueryruby-on-railsunobtrusive-javascriptruby-on-rails-5

How do I prepend/append this div as the last child of all the children as opposed to the first?


So I have a view that has renders HTML that looks like this :

enter image description here

What is happening now is when the user adds a new comment, it is now added to the top of that list, i.e. the div.social-comment that is highlighted. However, I want it to be added after the last in the list, not as the first. How do I do that?

This is what the create.js.erb looks like:

$(".question-<%= @comment.commentable.id %>").prepend("<%= j (render partial: 'comments/comment', locals: { comment: @comment}) %>");

How can I achieve what I want?

Edit 1

My bad, I wasn't fully clear with the original question.

I can't just use .append, due to the presence of a form field that is currently at the bottom of that list of children.

If I do use append, this is what the modified HTML looks like:

enter image description here

Note the .row .question-46-new appears before the last .social-comment.

So that ends up producing this:

screenshot-of-rendered-comments

Which is obviously what I don't want.

What I want is for the new comment to appear right above that Write Comment textbox, and at the end of the list of existing comments.

Edit 2

This is what my DOM tree looks like after attempting Pranav's suggestion:

enter image description here

Edit 3

After the latest attempt from Pranav, these are the results.

I tried this:

$(".question-<%= @comment.commentable.id %>").children(".social-comment").last().after("<%= j (render partial: 'comments/comment', locals: { comment: @comment}) %>");

That works well when there are existing comments, it just adds it to the last of the existing ones. When there are no existing comments though, the new comment just disappears.

Here is a picture of the DOM tree when there are no comments:

enter image description here

Here is a picture of the DOM tree after the comment has been added, using the above .js.erb:

enter image description here

No change. For what it's worth, I also tried it with the other suggestion:

$(".question-<%= @comment.commentable.id %> > .social-comment:last").after("<%= j (render partial: 'comments/comment', locals: { comment: @comment}) %>");

And I get similar behavior. It works when there are existing comments, but doesn't work when there are none.

Edit 4

When I use the :before suggestion from Pranav, this is the result.

This is what my comment section looks like when I add one comment, when there was none before (notice the spacing is off and the alignment with the other DOM elements looks weird):

not aligned going from 0 to 1 comment

Then this is what it looks like when there is an existing comment (notice how weird the alignment looks):

not aligned going from 1 to 2 comments

But if I refresh, this is what it looks like (which is how it should look, but just not how it looks immediately after the comment is added):

aligned on refresh


Solution

  • Use append() instead of prepend() method.

    $(".question-<%= @comment.commentable.id %>").append("<%= j (render partial: 'comments/comment', locals: { comment: @comment}) %>");
    


    UPDATE 1:

    Since you are updated the question, you can't do it using above code. Instead what you can do is get the last social-comment element inside the div and then append it after the element. You can use :last to get the last one and after() method to append after the last element.

    $(".question-<%= @comment.commentable.id %> .social-comment:last").after("<%= j (render partial: 'comments/comment', locals: { comment: @comment}) %>");
    

    UPDATE 2:

    Since there is nested div with same class you need to get only direct children instead. So either use child selector (>)

    $(".question-<%= @comment.commentable.id %> > .social-comment:last").after("<%= j (render partial: 'comments/comment', locals: { comment: @comment}) %>");
    

    or use children() and last().

    $(".question-<%= @comment.commentable.id %>").children(".social-comment").last().after("<%= j (render partial: 'comments/comment', locals: { comment: @comment}) %>");
    

    Also if the last div's class is always in format like parent id followed by -new(eg: question-36 and question-36-new) then you can done it using before() method.

    $(".question-<%= @comment.commentable.id %>-new").before("<%= j (render partial: 'comments/comment', locals: { comment: @comment}) %>");