0

I have this 10 elements with the class name "heroes". I made them clickable with a jQuery ".click" event. After clicking them, I made them change their classname with the ".attr" function. And they do, when I inspect them, they changed their class name to "fixheroes".

However, that doesn't stop the ".click" event to still function on them. And I don't want that.

You can find the code here:

http://codepen.io/anon/pen/KaMBmM

jQuery / JS

var counter = 1;
var picked = ["0", "0", "0", "0", "0", "0", "0"]

$(".heroes").click(function(e) {


    var id = this.id;
    var heroInt = id.substring(1, 3);

    picked[counter] = heroInt;




    var left = ["0", "21.5%", "32.9%", "44.3%", "55.7%", "67.1%", "21.5%", "32.9%", "44.3%", "55.7%", "67.1%"];


    $("#" + id).attr('class', "fixheroes fix" + heroInt);


    var h0 = document.getElementsByClassName('h0');
    var fixnow = document.getElementsByClassName("fix" + heroInt);
    fixnow[0].style.left = left[heroInt];

    if (heroInt > 5) {
        fixnow[0].style.top = (h0[0].offsetHeight + h0[0].getBoundingClientRect().top)



    } else {
        fixnow[0].style.top = "10%"

    }


    var ani = ".fix" + heroInt;



    if (counter == 1) {
        $(ani).animate({

            top: "5%",
            left: "3%",

        }, 1000, function() {});
    }

    if (counter == 2) {
        $(ani).animate({

            left: "85.6%",
            top: "5%",

        }, 1000, function() {});
    }
    if (counter == 3) {
        $(ani).animate({

            left: "3%",
            top: "35%",

        }, 1000, function() {});
    }
    if (counter == 4) {
        $(ani).animate({

            left: "85.6%",
            top: "35%",

        }, 1000, function() {});
    }
    if (counter == 5) {
        $(ani).animate({

            left: "3%",
            top: "65%",

        }, 1000, function() {});
    }
    if (counter == 6) {
        $(ani).animate({

            left: "85.6%",
            top: "65%",

        }, 1000, function() {});
    }



    counter += 1;


});

CSS:

.h {
    align-self: center;
    width: 96%;
    height 100%;
    border-style: solid;
    border-width: 0px;
    border-color: 817B6F;
}
.heroes {
    display: flex;
    justify-content: center;
    background-color: 817B6F;
    position: absolute;
    width: 10%;
    height: auto;
    padding: 0.7%;
    border-width: 1px;
    border-color: black;
    border-style: solid;
}

.fixheroes {
    display: flex;
    justify-content: center;
    background-color: 817B6F;
    position: absolute;
    width: 10%;
    height: auto;
    padding: 0.7%;
    border-width: 1px;
    border-color: black;
    border-style: solid;
}

.h0 {left: -20%; top:10%}
.h1 {left: 21.5%; top:10%;  border-top-left-radius: 5px;}
.h2 {left: 32.9%; top:10%;}
.h3 {left: 44.3%; top:10%;}
.h4 {left: 55.7%; top:10%;}    
.h5 {left: 67.1%; top:10%; border-top-right-radius: 5px; top:10%;}
.h6 {left: 21.5%; top:50%; border-bottom-left-radius: 5px;}
.h7 {left: 32.9%; top:50%;}
.h8 {left: 44.3%; top:50%;}
.h9 {left: 55.7%; top:50%;}    
.h10{left: 67.1%; top:50%; border-bottom-right-radius: 5px;}

HTML:

<div class="heroes h1" id="h1" >
<img class= "h" name= "Warrior" src="https://placehold.it/256" />
</div>


<div class="heroes h2" id="h2">
 <img class= "h" name= "Warrior" src="https://placehold.it/256" />
</div>



<div class="heroes h3" id="h3">
<img class= "h" name= "Warrior" src="https://placehold.it/256" />
</div>


<div class="heroes h4" id="h4">
<img class= "h" name= "Warrior" src="https://placehold.it/256" />
</div>

<div class="heroes h5" id="h5">
<img class= "h" name= "Warrior" src="https://placehold.it/256" />
</div>

<div class="heroes h6" id="h6">
<img class= "h" name= "Warrior" src="https://placehold.it/256"/>
</div>

<div class="heroes h7" id="h7">
<img class= "h" name= "Warrior" src="https://placehold.it/256" />
</div>


<div class="heroes h8" id="h8">
<img class= "h" name= "Warrior" src="https://placehold.it/256" />
</div>

<div class="heroes h9" id="h9">
<img class= "h" name= "Warrior" src="https://placehold.it/256" />
</div>

<div class="heroes h10" id="h10">
<img class= "h" name= "Warrior" src="https://placehold.it/256" />
</div>

I made a test function where this method does work:

http://codepen.io/anon/pen/LxZrKO

So what is the problem with my code?

4 Answers 4

5

That is because when an event is bound, it is bound to the DOM node based on the selector criteria. Once it is bound, the event listener will always be active unless removed. In this case, the click event handler is bound to all .heroes element on DOM ready, and even after changing their classes, these DOM nodes will have the click event bound.

To account for dynamic class changes (so that changes in classes will "remove" the event handler), simply bind the click event handler to a higher level parent (or the document object). In my honest opinion this is the way I would solve your issue, instead of having to go through the messy unbind() or off() methods.

$(document).on('click', '.heroes', function(e) { ... }

The .on() event will automatically filter for click events coming from any child nodes that has the class heroes. Therefore, if the classes are being updated dynamically, this trick will still work. Along the same vein, this is why .on() + a filtering selector is the recommended way to bind events to dynamically added elements. In this case, instead of a dynamic class change, we are looking for dynamically added elements.

Here is your updated fiddle with a single line change: http://codepen.io/anon/pen/BpzPVN

Also, with regards to the minimal example, the same fix will also be equally valid:

$(document).on('click', '.test', function(e) { 
   console.log('Class changed to test2');
   $(".test").attr('class', "test2");
});
.test {
  position: absolute;
  height: 200px;
  width: 200px;
  background-color: red;
}

.test2 {
  position: absolute;
  height: 200px;
  width: 200px;
  background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="test">
  click me
</div>

Sign up to request clarification or add additional context in comments.

Comments

0

The `.click()' handler is tied to the element itself, not your class selector. You can make it stop working in a couple of different ways.

  1. Before you change the class, also remove the handler: $(".heroes").off("click");

  2. Put the handler on the parent instead of the child: $("#parentdiv").on("click", ".heroes", function() {});

Comments

0

The click handler is added once, immediately when the code is run. It'll now listen to clicks on that element forever, no matter what you do to the element.

When you say $(".heroes").click, you're not saying "Only trigger click events on things that have the .heroes class". You're saying "Add a click event to everything that has a .heroes class right now."

The way I fixed it was to add $(this).unbind("click"); to the beginning of your function to remove the click handler.

Comments

0

The problem is that the event handler is still attached to the element. to fix just add $("#" + id).off("click"); before you change the class.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.