Rabbit Rabbit - 3 months ago 7
HTML Question

Dynamic bootstrap modals in Rails application not working

I'm creating a simple app and I'm trying to add dynamically generated modals like this:

<% @friends.each do |friend| %>
<div class = "row user">
<div class = "col-sm-4" >
<img class="friend-picture" src=" <%= friend["image"][2]["content"] %> ">
</div>
<div class = "col-sm-4">
<h4 class="user-name text-center"><%= friend["name"] %> </h4>
<ul class="list-group">
<% @lastfm.getFriendTracks(friend["name"]).each do |track| %>
<li class="list-group-item"> <%= track["artist"]["content"] %> - <%= track["name"] %>
<br>
<div class="text-right comments">
<a type="button" data-toggle="modal" data-target="#comments_<%=track["artist"]["content"]%>_<%=track["name"]%>">3 comments</a>
</div>

<div id="comments_<%=track["artist"]["content"]%>_<%=track["name"]%>" class = "modal fade" role = "dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">
<%= track["artist"]["content"] %> - <%= track["name"] %>
</h4>
</div>
<div class="modal-body text-center container" style="max-width:570px">
<ul class = "list-group" >
<li class = "list-group-item text-left">
<div class = "author">
<p> Author </p>
</div>
<div class = "comment">
<p> Comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment </p>
</div>
</li>

<li class = "list-group-item text-left">
<div class = "author">
<p> Author </p>
</div>
<div class = "comment">
<p> Comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment </p>
</div>
</li>

<li class = "list-group-item text-left">
<div class = "author">
<p> Author </p>
</div>
<div class = "comment">
<p> Comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment comment </p>
</div>
</li>
</ul>

<textarea name="comment" cols="74" rows="3"></textarea>
<div class = "text-right">
<button type="button" class="btn btn-default" >Submit</button>
</div>


</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close
</button>
</div>
</div>
</div>
</div>
</li>
<% end %>
</ul>
</div>
</div>
<% end %>


As you can see each friend has some songs and for each song there can be comments. I'm trying to call the popups by dynamically generated id, but - funny thing - only the first one works... When I click comments button on the firs song (or it's later appearances) it works, but the rest of them doesn't.

enter image description here

In the inspector I can see that all the modals' ids are generated correctly.

I'm running out of ideas what to do about this.

Answer

Use <%= track["artist"]["content"].parameterize %> and <%= track["name"].parameterize %> when creating the element ids. This will make your text from #comments_Blues Pills_Lady In Gold to comments_blues-pills_lady-in-gold.

Your link to display the modal would look like

<%= link_to '3 comments', '#', data: { toggle: 'modal', target: "#comments_#{track["artist"]["content"].parameterize}_#{track["name"].parameterize} %>

Unrelated, You should use content_tag for your div tags. It makes it easier to read in my opinion.

<div id="comments_<%=track["artist"]["content"]%>_<%=track["name"]%>" class = "modal fade" role = "dialog">
  ...
</div>

Would look like

<%= content_tag :div, id: "comments_#{track["artist"]["content"].parameterize}_#{track["name"].parameterize}", class: 'modal fade', role: 'dialog' do %>
  ...
<% end %>

The same would apply to your images

<img class="friend-picture" src=" <%= friend["image"][2]["content"] %>   ">

Would be

<%= content_tag :img, nil, class: 'friend-picture', src: "#{friend["image"][2]["content"]} %>

Notice the nil passed as this would be an empty element instead of making a block.

Keep in mind that you're also creating a lot of potential overhead. Unless you know that you're users will be clicking on each track of their friends on the page, you are essentially wasting bandwidth and render time. Once a user has a lot of friends and a lot of tracks, the page load could be rather large (even if caching is used). A better option would be to dynamically generate the modal on the server side when the user clicks on the like. I recorded a screencast covering this type of topic. https://www.driftingruby.com/episodes/not-rjs-and-turbolinks-part-2