Search code examples
javascriptjqueryevent-handlingonclicklistenerjquery-events

Jquery Element class doesn't exists but event still fires


I have this bit of code.

Red, Green and blue have to be shown in order when clicking on button, but click event propagates directly to blue without green. When I use e.stopproagation then jQuery event listener is still attached to element class which doesn't exist.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Basket | Placelyrics</title>
    <link rel="stylesheet" href="normalize.css">
    <link rel="stylesheet" href="index.css">
    <script src="jquery.js"></script>
    <script src="a.js"></script>
    <script>
        $(document).ready(function(){
            $('.div1shown').click(function(event){
                $('.red').hide();
                $('.green').show();
                $(this).removeClass('div1shown').addClass('div2shown');
                console.log('a');
                
            });

            $('.container').delegate('.div2shown', 'click', function(event) {
                $('.green').hide();
                $('.blue').show();
                $(this).removeClass('div2shown').addClass('div3shown');
                console.log('b');
            });
        });
    </script>
    <style>
        .box{
            width:200px;
            height:200px;
            display: block;
        }

        .red{
            background-color: red;
        }

        .green{
            background-color: green;
            display:none;
        }

        .blue{
            background-color: blue;
            display:none;
        }

    </style>
</head>
<body>

<div class="container">
        <div class="box red">
            
        </div>

        <div class="box green">
            
        </div>

        <div class="box blue">
            
        </div>

        <button class="div1shown">submit</button>
</div>

</body>
</html>

Solution

  • You need to use event delegation for the first event handler also

    $(document).ready(function() {
      $('.container').delegate('.div1shown', 'click', function(event) {
        $('.red').hide();
        $('.green').show();
        $(this).removeClass('div1shown').addClass('div2shown');
        console.log('a');
    
      });
    
      $('.container').delegate('.div2shown', 'click', function(event) {
        $('.green').hide();
        $('.blue').show();
        $(this).removeClass('div2shown').addClass('div3shown');
        console.log('b');
      });
    });
    .box {
      width: 200px;
      height: 200px;
      display: block;
    }
    .red {
      background-color: red;
    }
    .green {
      background-color: green;
      display: none;
    }
    .blue {
      background-color: blue;
      display: none;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    
    <div class="container">
      <div class="box red">
      </div>
    
      <div class="box green">
      </div>
    
      <div class="box blue">
      </div>
    
      <button class="div1shown">submit</button>
    </div>

    When you use a normal event handler registration as you have done in the first case, the selector is evaluated only one at the registration phase after that the selector is never evaluated that is why even after you change the class the first handler is getting executed. But when you use a delegated event handler the target element selector is executed lazily so it can accommodate changes happened to the element at a later stage.