Xullnn
Xullnn

Reputation: 405

Why jquery toggleClass() only works in even siblings?

I have DOM like this in a Rails app:

<div class="post_info">
  <div class="col">
    <i class="post_comments">icon</i>
  </div>
</div>
<div class="comments_body">
  <ul>
    <li>Many comments.</li>
  </ul>
</div>

My target is hide and show '.comments_body' element right below the '.post_comment' icon which I clicked.

I've tried this:

css

.comments_body {
   display: none;
 }

.active {
   display: block;
 }

What I was trying to is target the icon's 'grandparent's next sibling', means the comments_body relating to this icon, then toggle it's display style.

my jquery code:

<script>
    $(".post_info").click(function(event) {
      $(event.target).parent().parent().next().toggleClass('active');
    });
</script>

But it turns out this only works on even comments_body like the 2nd ,4th ,6th ,8th. I checked dev tool, when I click on odd icon, the event wasn't be triggered.

How to solve this? Or is there better way to achieve this effect?

Update:

I tried the answers below but still not work. I put the page's github address here. Since it's a Rails app, you might need to clone it to local and try it. If so, run seed to generate fake data. Thanks!

Upvotes: 1

Views: 116

Answers (2)

user9467714
user9467714

Reputation:

    $(".post_info").click(function(event) {
   
          $(event.target).parent().parent().next().toggleClass('active');
        });
    .comments_body {
       display: none;
     }

    .active {
       display: block !important;
     }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div class="post_info">
      <div class="col">
        <i class="post_comments">icon</i>
      </div>
    </div>


    <div class="comments_body">
      <ul>
          <li>Many comments.</li>
      </ul>
    </div>
    <div class="post_info">
      <div class="col">
        <i class="post_comments">icon</i>
      </div>
    </div>
    <div class="comments_body">
      <ul>
        <li>Many comments.</li>
      </ul>
    </div>
    <div class="post_info">
      <div class="col">
        <i class="post_comments">icon</i>
      </div>
    </div>
    <div class="comments_body">
      <ul>
        <li>Many comments.</li>
      </ul>
    </div>

I have made a example for you. It working fine. I dont see any problem in case of even odd selection. try making important your active element as

.active {
  display: block !important;
 }

if it still not creating desired result kindly let me know. I will put my code here. Cheers....

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1075925

First, you need to remove the : from this:

.comments_body: { /* <==== Remove that : */
  display: none;
}

Then, this within your event handler is the .post_info element, so you can use that instead of $(e.target).parent().parent() which is inherently fragile (both because a small change to your markup breaks it, and because if you click within the .post_info but outside the icon, it will be wrong — which I suspect is why you're seeing the inconsistent behavior).

$(".post_info").click(function(event) {
    $(this).next().toggleClass('active');
});

Live Example:

$(".post_info").click(function(event) {
  $(this).next().toggleClass('active');
});
.comments_body {
  display: none;
}

.active {
  display: block;
}
<div class="post_info">
  <div class="col">
    <i class="post_comments">icon 1</i>
  </div>
</div>
<div class="comments_body">
  <ul>
    <li>Many comments 1.</li>
  </ul>
</div>
<div class="post_info">
  <div class="col">
    <i class="post_comments">icon 2</i>
  </div>
</div>
<div class="comments_body">
  <ul>
    <li>Many comments 2.</li>
  </ul>
</div>
<div class="post_info">
  <div class="col">
    <i class="post_comments">icon 3</i>
  </div>
</div>
<div class="comments_body">
  <ul>
    <li>Many comments 3.</li>
  </ul>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


Side note: You might consider using event delegation for that handler rather than hooking the event on each individual .post_info. That way, if you add and remove .post_info instances at runtime, the handler will keep working.

Presumably these are in some kind of container, so you'd use:

$("selector-for-the-container").on("click", ".post_info", function(event) {
    $(this).next().toggleClass('active');
});

Live Example:

$("#container").on("click", ".post_info", function(event) {
  $(this).next().toggleClass('active');
});

// Works on #4 even though we add it later:
setTimeout(function() {
  $("#container").append(
    '<div class="post_info">' +
      '<div class="col">' +
        '<i class="post_comments">icon 4</i>' +
      '</div>' +
    '</div>' +
    '<div class="comments_body">' +
      '<ul>' +
        '<li>Many comments 4.</li>' +
      '</ul>' +
    '</div>'
  );
}, 800);
.comments_body {
  display: none;
}

.active {
  display: block;
}
<div id="container">
  <div class="post_info">
    <div class="col">
      <i class="post_comments">icon 1</i>
    </div>
  </div>
  <div class="comments_body">
    <ul>
      <li>Many comments 1.</li>
    </ul>
  </div>
  <div class="post_info">
    <div class="col">
      <i class="post_comments">icon 2</i>
    </div>
  </div>
  <div class="comments_body">
    <ul>
      <li>Many comments 2.</li>
    </ul>
  </div>
  <div class="post_info">
    <div class="col">
      <i class="post_comments">icon 3</i>
    </div>
  </div>
  <div class="comments_body">
    <ul>
      <li>Many comments 3.</li>
    </ul>
  </div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Upvotes: 3

Related Questions