javascripthtmlelixir

Javascript not working as expected when show/ hide


I am trying to render a list of goals saved on the database on an index page, and to create a unique id for the divs, I added the goal_id to the id, like this:

    <%= for goal <- @goals do %>
      <p class="text-black block text-xl leading-snug mt-3">
        <%= goal.description %>
      </p>
       <div class="text-gray-500 dark:text-gray-400 flex mt-3">
         <div class="flex items-center mr-6" onclick="showComments()">
          <span class="ml-3"><%= Enum.count(goal.comments) %> comments</span>
         </div>
        </div>

          <div id={"goal-#{goal.id}"} class="goal_comments">
            <ul role="list" class="space-y-6">
              <li class="relative flex gap-x-4">
                <div class="absolute left-0 top-0 flex w-6 justify-center -bottom-6">
                  <div class="w-px bg-gray-200"></div>
                </div>
                <div class="relative flex h-6 w-6 flex-none items-center justify-center bg-white">
                  <div class="h-1.5 w-1.5 rounded-full bg-gray-100 ring-1 ring-gray-300"></div>
                </div>
              </li>
              <%= for goal_comment <- goal.comments do %>
                <li class="relative flex gap-x-4">
                  <div class="absolute left-0 top-0 flex w-6 justify-center -bottom-6">
                    <div class="w-px bg-gray-200"></div>
                  </div>
                  
                  <div class="flex-auto rounded-md p-3 ring-1 ring-inset ring-gray-200">
                    <div class="flex justify-between gap-x-4">
                      <div class="py-0.5 text-xs leading-5 text-gray-500"><span class="font-medium text-gray-900"><%= goal_comment.creator.username %></span> commented</div>
                      
                    </div>
                    <p class="text-sm leading-6 text-gray-500"><%= goal_comment.comment %></p>
                  </div>
                </li>
              <% end %>
            </ul>
        

            <script>
              function showComments() {
                console.log("goal-<%= goal.id %>")
                var comments = document.getElementById("goal-<%= goal.id %>");

                if (comments.style.display === "none") {
                  comments.style.display = "block";
                } else {
                  comments.style.display = "none";
                }
              }
            </script>
          </div>
        </div>
      </div>
  <% end %>

I am using JS to be able to hide and show this div as required by the user. When I check my console, I see that in all the div components the id is unique, the problem is if I have more than 1 entries, which makes it 2 or more div components, when I click on the word comments the last div component is what takes the action of being shown/ hidden. So, my question is, what am I doing wrong?

I also see these error show up on my console: enter image description here


Solution

  • You should pass the specific id to showComments():

    <div class="flex items-center mr-6" onclick="showComments(<%= goal.id %>)">
      <span class="ml-3"><%= Enum.count(goal.comments) %> comments</span>
    </div>
    

    Then use that id:

    <%= for goal <- @goals do %>
      <!-- ... Existing HTML code ... -->
    
      <script>
        function showComments(goalId) {
          var comments = document.getElementById("goal-" + goalId);
    
          if (comments.style.display === "none") {
            comments.style.display = "block";
          } else {
            comments.style.display = "none";
          }
        }
      </script>
    <% end %>