Add class to parent only when child has an active class

Viewed 193

I have a masonry, sometimes masonry-item has class 'open'. I want add to masonry class opacity, only when some mansory-item has open. If mansory-item childs didnt have open class, then mansory should have class opacity. The If statment its working only the first part, but i dont know to solve it. I edited and updated.

$("masonry-item .bottom-line").click(function () {
    $('masonry-item.open').not($(this).parent()).removeClass('open');
    $(this).parent().toggleClass('open');
    $('masonry-item').each(
      function(){
          if ($(this).has('.open')){
            $(this).parent().addClass('error');
              } else {
            $(this).parent().removeClass('error');
          }
      }); 
      
  });



  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div class="masonry">
      <div class="masonry-item"></div>
      <div class="masonry-item"></div>
    </div>
5 Answers

In your code if ONE of them has ONE of the classes or not, the parent will be set - you want to use .some or similar

Clicking the divs opens them and tests if the container should change class

Clicking outside removes class open

$(function() {
  const $container = $('.masonry');
  const testOpen = () => {
    $container.toggleClass("error",
      $container.find(".open").length > 0
    );
  }
  $('.masonry-item').on("click", function() {
    $(this).toggleClass("open");
    testOpen()
  });

  $(document).on("click", function(e) {
    if (!$container.is(e.target) && $container.has(e.target).length === 0) {
      $container.find(".open").removeClass("open");
      testOpen()
    }
  });
});
.error {
  color: red;
  border: 1px solid black;
  display: inline-block;
}

.open {
  font-weight: bold;
  text-decoration: underline;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="masonry">
  <div class="masonry-item">One</div>
  <div class="masonry-item">Two</div>
  <div class="masonry-item">Three</div>
  <div class="masonry-item">Four</div>
</div>

outside

I think the solution depends mainly on your logic where you open the items :) that would be where you check if you want to add that class. You havent added any code, so a generic answer:

$('.masonry-item').on('click', function(e){
    e.preventDefault();
    $(this).toggleClass('active'); // toggle the item
    
    // Check of the parent masonry has any active children:
    const hasActives = 0 !== $(this).closest('masonry').find(.masonry-item.active).length;
    // add/remove the class depending on the previous result:
    $(this).closest('masonry').toggleClass('hasActiveChild', hasActives)
});

Since logically if at least one item has .open, you do not have to worry about the rest of the .masonry-item. My guess is that your code is not working for cases like ['','open','']. Iteration 3 removes the class even though the 'opacity' class was set at iteration two.

$('.masonry-item').each(function() {
      if ($(this).has('.open')) {
        $(this).parent().addClass('opacity');
        return false; // breaks
      } else {
        $(this).parent().removeClass('opacity');
      }
    });

The problem with your current approach is, say you have 3 items, and the second one has the "open" class; your script is going to test each item one after the other, then turn the parent's class off, on, then off again. This script will only work when your last item has the desired class, because then, it won't be overriden.

You need to check if there's at least one item with the class, anywhere. If yes, turn on the parent's class. You can do it with find(), which is much less greedy than iterating every item :

const $container = $(".masonry");
const hasOpenItem = !!$container.find(".masonry-item.open");
$container[ hasOpenItem ? "addClass" : "removeClass" ]('opacity');

instead of looping all the children of the outer class check if the paren has children with class open

if($('.masonry').find('.open').length !== 0){
      $('.masonry').addClass('opacity');
}else{
 $('.masonry').removeClass('opacity');
}
Related