Search code examples
javascriptjqueryhtmlremoveclass

Why doesn't this jquery (hover) effect get called when the conditions (removeClass) are met?


Here is the code link http://codepen.io/anon/pen/kzJvl (full code below)

The code should remove all instances of the class .gigante

$('.gigante').removeClass('gigante');

so therefore the hover effect which works on all the items without .gigante

$civs.hover(function() {
    $(this).addClass("colorise");
}, function() {
    $(this).removeClass("colorise");
});

should be active on all the elements in the code? should it not?

Yet the second div item still appears to have a remnant of that class or something I don't comprehend

Full code of pen:

JavaScript:

var $gigante = $('.gigante');
var $civs = $(".civ-item:not(.gigante)");

// HOVER
$civs.hover(function() {
    $(this).addClass("colorise");
}, function() {
    $(this).removeClass("colorise");
});

// REMOVE CLASS
$civs.bind('click', function() {
    $('.gigante').removeClass('gigante');
});

CSS:

.civ-item{
 float:left;
 background-color: #2D2D2D;
 width: 238px;
 height: 160px;
 border: 1px solid red;
 margin-bottom: 2px;
 }
 .gigante {
    width: 478px;
    height: 600px;
 }
.colorise {
  background-color: blue;
}

HTML:

<div class="remove"></div>
     <div id="container" class="clearfix">
        <div class="civ-item"></div>
        <div class="civ-item gigante"></div>
        <div class="civ-item"></div>
        <div class="civ-item"></div>
</div>

Solution

  • should be active on all the elements in the code? should it not?

    No, because your $civs variable was filled in with the list of elements before you removed the class.

    You have at least three options:

    1. Event delegation - You hook the event on a container of the elements in question (ideally something close to them, but you can use document in the worst case), but tell jQuery you only care about the event if it passed through something matching the selector. In your case, you'd hook mouseenter for your entering logic and mouseleave for your exiting logic.

      var $gigante = $('.gigante');
      
      // HOVER
      $(document)
        .on("mouseenter", ".civ-item:not(.gigante)", function() {
          $(this).addClass("colorise");
        })
        .on("mouseleave", ".civ-item:not(.gigante)", function() {
          $(this).removeClass("colorise");
        })
      ;
      
      // REMOVE CLASS
      $(".civ-item").bind('click', function() {
        $('.gigante').removeClass('gigante');
      });
      
    2. When you remove the class from the elements, re-query the new set of $civs elements an rebind your handler:

      function civsHandler() {
          $('.gigante').removeClass('gigante');
          $civs = $(".civ-item:not(.gigante)"); // Of course, there aren't any anymore,
                                                // but I'm allowing for the case where
                                                // you only remove some or something
          $civs.unbind('click').bind('click', civsHandler);
      }
      $civs.bind('click', civsHandler);
      
    3. Bind to all .civ-item elements:

      var $civs = $(".civ-item");
      

      ...and check when the hover occurs whether it has the gigante class:

      $civs.hover(function() {
        if (!$(this).hasClass("gigante")) {
          $(this).addClass("colorise");
        }
      }, function() {
        if (!$(this).hasClass("gigante")) { // You may or may not want this check
          $(this).removeClass("colorise");
        }
      });