2

I'm creating a little application and I can't figure out why selecting items isn't working on it. I tried it using toggleClass(), but it had the same impact. Toggle class 'selected' only works on odd elements.

http://codepen.io/sobrancelhas/pen/ENQvgy

    $(document).ready(function() {

    $('#options :checkbox').change(function() {
        if (this.checked) {
            $('#botao').addClass('adicionar');
            $('#botao').html('Add');
        } else {
            $('#botao').removeClass('adicionar');
            $('#botao').html('Remove');
        }
    });

    $('#botao').click(function() {
        if($(this).hasClass('adicionar')){
            $('#container').append('<div class="item">ITEM</div>');
        } else {
            $('#container').find(".item:last").remove();
        }

        $('.item').click(function(){
                if($(this).hasClass('selected')){
                    $(this).removeClass('selected');
                } else {
                    $(this).addClass('selected');
                }
        });

    });

});

2 Answers2

3
  1. The $('.item').click(function(){ function should not be inside the $('#botao').click(function() { function.
  2. You should change the $('.item').click(function(){ to $(document).on('click', '.item' to support also new elements that you add after the page was loaded.

Here is the fix:

$(document).ready(function() {

  $('#options :checkbox').change(function() {
    if (this.checked) {
      $('#botao').addClass('adicionar');
      $('#botao').html('Add');
    } else {
      $('#botao').removeClass('adicionar');
      $('#botao').html('Remove');
    }
  });

  $('#botao').click(function() {
    if($(this).hasClass('adicionar')){
      $('#container').append('<div class="item">ITEM</div>');
    } else {
      $('#container').find(".item:last").remove();
    }
  });

  $(document).on('click', '.item', function(){
    if($(this).hasClass('selected')){
      $(this).removeClass('selected');
    } else {
      $(this).addClass('selected');
    }
  });
});
body{
font-family: Cambria, Hoefler Text, Liberation Serif, Times, Times New Roman, serif;
}

#options{
display: block;
position: relative;
}

#botao {
position: absolute;
top: 0;
left: 83px;
height: 34px;
display: flex;
padding: 9px 13px;
border: none;
background: #f56363;
color: #fff;
-webkit-transition: .4s;
transition: .4s;
}
#botao.adicionar{
background:#2196F3;
}

.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}

.switch input {display:none;}

.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #f56363;
-webkit-transition: .4s;
transition: .4s;
}

.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}

input:checked + .slider {
background-color: #2196F3;
}

input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}

input:checked + .slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}

/* Rounded sliders */
.slider.round {
border-radius: 34px;
}

.slider.round:before {
border-radius: 50%;
}

#container{
background: #b8e0f1;
min-height: 400px;
max-height: 600px;
overflow: auto;
width: 30%;
margin-top: 15px;
padding: 8px;
}

.item {
background: #607D8B;
width: 100%;
height: 25px;
margin-top: 8px;
color: #fff;
text-align: center;
padding-top: 4px;
}
 
.item.selected{
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
 <h1>Add, remove and select itens</h1>
 <div id="options">
  <label class="switch">
   <input type="checkbox" id="switch">
   <div class="slider"></div>
  </label>
  <button id="botao">Remove</button>
 </div>
 
 <div id="container">
 </div>
 
</body>
Dekel
  • 60,707
  • 10
  • 101
  • 129
  • nice explaination. But is there any other method like `$(document).on('click', '.item'` to capture click on the dynamic elements? – jafarbtech Dec 03 '16 at 16:31
  • 1
    You don't need any other method. Every `event` handlers works the same in jQuery. You can use `$('body').on('click', '.item'` or `$('body').on('mouseenter', '.item'`, etc.. – Dekel Dec 03 '16 at 16:32
  • 1
    Read more here: http://stackoverflow.com/questions/1359018/in-jquery-how-to-attach-events-to-dynamic-html-elements – Dekel Dec 03 '16 at 16:33
  • can i use more selectors in it like `$('.test, .test1').on('click', '.item, .menuitem'` ? – jafarbtech Dec 03 '16 at 16:34
  • 1
    Yes, but it doesn't really make any sense. Read more in the link in my previous comment. – Dekel Dec 03 '16 at 16:35
  • Thank you very much! It worked, but i didn't really understand... I thought I should delegate the event of clicking only after the first item is already created... What exactly the $(document).on does? – Talis Galhardi Dec 03 '16 at 16:39
  • This is **exactly** what the `$(document).on` does. Did you read the explanation in the link? – Dekel Dec 03 '16 at 16:40
2

It's because everytime user clicks on #botao you attach new handlers to all your .items

You can do something like that instead:

$(document).ready(function() {

    $('#options :checkbox').change(function() {
        if (this.checked) {
            $('#botao').addClass('adicionar');
            $('#botao').html('Add');
        } else {
            $('#botao').removeClass('adicionar');
            $('#botao').html('Remove');
        }
    });

    $('#botao').click(function() {
        if($(this).hasClass('adicionar')){
            $('#container').append('<div class="item">ITEM</div>');

            // adding handler only to the last item - which we've just added
            $('.item:last').click(function(){
                    $(this).toggleClass('selected');
            });
        } else {
            $('#container').find(".item:last").remove();
        }
    });

});
Marcin Krawiec
  • 703
  • 3
  • 8