Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

input type checkbox with labels firing events twice

I am trying to dynmaically create round checkboxes with tickMark which get appended to id="demo" onclick of two buttons which call get(data) method.

The issue is when two buttons called simulataneously, checkbox is not getting tick mark and causing call of getdata(idD + '_chckBox') method twice or more as seen in console.log.

However, I am using e.preventDefault(); e.stopPropagation();.

What is the issue here, the getdata(idD + '_chckBox') is called twice or more and roundcheckbox is not getting checked?

I am trying to toggle checkbox and show tick mark. If any better way of doing this possible, is also welcomed.

what is the best and easiest way to bind onclick and onscroll method in dynamic htmls which are in for loop, so that a object can be passed as a parameter in called method onclick.

index.html

   

     var data0 = [{
            "title": "a"
          },
          {
            "title": "b"
          },
          {
            "title": "c"
          },
          {
            "title": "d"
          },
        ];
        var data1 = [{
            "title": "ads"
          },
          {
            "title": "bd"
          },
          {
            "title": "fc"
          },
          {
            "title": "dg"
          },
        ];
    
     var html = "<div id='parent'   ' + 'onscroll="loadMoreContent(event)" ></div>";
     $(html ).appendTo('body');
        $(document).on('click', '#btn11', () => {
          get(data0, 'parent');
        })
        $(document).on('click', '#btn00', () => {
          get(data1,'parent');
        })
    
function loadMoreContent(event){
 // gettting server data (data01 ) on ajax call
var data01 = [{
            "title": "aaa"
          },
          {
            "title": "sdw3b"
          },
          {
            "title": "c433"
          },
          {
            "title": "34d"
          },
        ];
get(data01 , idToAppend)
}
        function get(data, idToAppend) {
    
          var html = '';
          html += '<div class="col-12 parentdiv">';
          $.each(data, function(key, msgItem) {
            var idD = msgItem.title + key;
            html += '<div class="flLeftBlock"  style="width: 30px;margin-top: 36px;">';
            html += '<div class="roundCheckboxWidget"  id="' + idD + '_roundCheckboxWidget">';
            html += '<input   id="' + idD + '_chckBox" class="" type="checkbox" tid="" title="discard">';
            html += '<label id="' + idD + '_chckBox_label" for="' + msgItem.title + '" ></label> ';
            html += "&nbsp;" + msgItem.title;
            html += '</div>';
            html += '</div>';
            html += '';
          });
          html += '</div>';
          $('#'+ idToAppend).append(html);
    
          $.each(data, function(index, element) {
            var idD = element.title + index;
            const self = this;
            $(document).on('click', '#' + idD + '_chckBox_label', (e) => {
              if (e.target.tagName === "LABEL") {
                e.preventDefault();
                e.stopPropagation();
                console.log('#' + idD + '_chckBox_label');
                getdata(idD + '_chckBox');
              }
            });
          });
        }
    
        function getdata(id) {
          console.log(id);
          $("#" + id).prop("checked", !$("#" + id).prop("checked"));
          return true;
        }
.roundCheckboxWidget {
  position: relative;
}

.roundCheckboxWidget label {
  background-color: #ffffff;
  border: 1px solid rgb(196, 196, 209);
  border-radius: 50%;
  cursor: pointer;
  height: 22px;
  left: 0;
  position: absolute;
  top: 0;
  width: 22px;
}

.roundCheckboxWidget label:after {
  border: 2px solid #fff;
  border-top: none;
  border-right: none;
  content: "";
  height: 6px;
  left: 4px;
  opacity: 0;
  position: absolute;
  top: 6px;
  transform: rotate(-45deg);
  width: 12px;
}

.roundCheckboxWidget input[type="checkbox"] {
  visibility: hidden;
}

.roundCheckboxWidget input[type="checkbox"]:checked+label {
  /* background-color: #6168e7 !important;
      border-color: 1px solid #6168e7 !important; */
}

.roundCheckboxWidget input[type="checkbox"]:checked+label:after {
  opacity: 1;
}

.roundCheckboxWidget input[type="checkbox"]:checked+label {
  background-color: #ff5b6a;
  border-color: #ff5b6a !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p>Alternate click on two buttons without refreshing causing getdata() method call twice. </p>

<button id="btn11" onclick="get()">Try It</button>
<button id="btn00" onclick="get()">Try It2</button>
<div id="demo"></div>
like image 208
Manzer Avatar asked Mar 14 '19 03:03

Manzer


2 Answers

There is several mistakes here.

  1. You use some id that aren't unique. There is an attempt to make them unique, but you used the array key, which is static. So on every button click, duplicate ids are produced. You need a counter.
  2. You use an .each() loop to define a delegated event handler... Which is a misunderstanding of delegation.
  3. You use a function to toggle the checkbox state when the for= attribute on the label can do it without a single line of code.
  4. The loadMoreContent() function is unclear... I assumed you want an "infinite scroll"... So you have to check if the bottom of the page is reached to call the Ajax request... Else, you will fire tons of request on each scroll... up and down!

So here is how to do it:
   (See comment within code)

// checkbox title arrays
var data0 = [{ "title": "a" }, { "title": "b" }, { "title": "c" }, { "title": "d" }];
var data1 = [{ "title": "ads" }, { "title": "bd" }, { "title": "fc" }, { "title": "dg" }];

// Appends th "parent" div on load.
var html = "<div id='parent'></div>";
$(html).appendTo('body');

// Button handlers
$(document).on('click', '#btn11', () => {
  get(data0,'parent');
})
$(document).on('click', '#btn00', () => {
  get(data1,'parent');
})

// Simulated Ajax request... I assume.
function loadMoreContent(idToAppend){
  // gettting server data (data01 ) on ajax call
  var data01 = [{ "title": "aaa" }, { "title": "sdw3b" }, { "title": "c433" }, { "title": "34d" } ];
  get(data01 , idToAppend)
}

// Main function. It needs a counter to create UNIQUE ids.
var checkbox_counter = 0;
function get(data, idToAppend) {

  var html = '';
  html += '<div class="col-12 parentdiv">';
  $.each(data, function(key, msgItem) {
    html += '<div class="flLeftBlock" style="width: 30px;margin-top: 36px;">';
    html += '<div class="roundCheckboxWidget">';
    html += '<input id="checkbox_'+checkbox_counter+'" type="checkbox" tid="" title="discard">';
    html += '<label for="checkbox_'+checkbox_counter+'"></label> ';
    html += "&nbsp;" + msgItem.title;
    html += '</div>';
    html += '</div>';
    html += '';
    
    // Increment the checkbox counter
    checkbox_counter++;
  });
  html += '</div>';
  $('#'+ idToAppend).append(html);
}

// Just to console log the id of the checkbox...
$(document).on('click', 'label', function(){
  var checkbox_id = $(this).prev("[type='checkbox']").attr("id");
  console.log(checkbox_id);
});

// On scroll handler, check if the bottom of the page is reached to load some more...
$(document).on('scroll', function(){
  var scrolled = Math.ceil($(window).scrollTop());
  var viewport_height = $(window).outerHeight();
  var window_full_height = $(document).outerHeight();
  //console.log(scrolled +" "+ viewport_height +" "+ window_full_height);
  
  if(scrolled + viewport_height == window_full_height){
    console.log("reached the bottom... Loading some more!");
    
    // Call the Ajax request
    loadMoreContent("parent");
  }
});
.roundCheckboxWidget {
  position: relative;
}

.roundCheckboxWidget label {
  background-color: #ffffff;
  border: 1px solid rgb(196, 196, 209);
  border-radius: 50%;
  cursor: pointer;
  height: 22px;
  left: 0;
  position: absolute;
  top: 0;
  width: 22px;
}

.roundCheckboxWidget label:after {
  border: 2px solid #fff;
  border-top: none;
  border-right: none;
  content: "";
  height: 6px;
  left: 4px;
  opacity: 0;
  position: absolute;
  top: 6px;
  transform: rotate(-45deg);
  width: 12px;
}

.roundCheckboxWidget input[type="checkbox"] {
  visibility: hidden;
}

.roundCheckboxWidget input[type="checkbox"]:checked+label {
  /* background-color: #6168e7 !important;
  border-color: 1px solid #6168e7 !important; */
}

.roundCheckboxWidget input[type="checkbox"]:checked+label:after {
  opacity: 1;
}

.roundCheckboxWidget input[type="checkbox"]:checked+label {
  background-color: #ff5b6a;
  border-color: #ff5b6a !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p>Alternate click on two buttons without refreshing causing getdata() method call twice. </p>

<button id="btn11" onclick="get()">Try It</button>
<button id="btn00" onclick="get()">Try It2</button>
<div id="demo"></div>

CodePen

like image 181
Louys Patrice Bessette Avatar answered Sep 21 '22 21:09

Louys Patrice Bessette


There are two problems with code:

  • You are setting onclick="get()" and also adding click event using jQuery so it will trigger twice. remove onclick ="get()"
  • Second problem is that on every get() call it will add new click listeners to checkboxes. To prevent that use a boolean in your array only apply click event once

var data0 = [{
    "title": "a"
  },
  {
    "title": "b"
  },
  {
    "title": "c"
  },
  {
    "title": "d"
  },
  false
];
var data1 = [{
    "title": "ads"
  },
  {
    "title": "bd"
  },
  {
    "title": "fc"
  },
  {
    "title": "dg"
  },
  false
];
$(document).on('click', '#btn11', () => {
  get(data0);
})
$(document).on('click', '#btn00', () => {
  get(data1);
})

function get(data) {
  var html = '';
  html += '<div class="col-12 parentdiv"';
  $.each(data, function(key, msgItem) {
    var idD = msgItem.title + key;
    html += '<div class="flLeftBlock"  style="width: 30px;margin-top: 36px;">';
    html += '<div class="roundCheckboxWidget"  id="' + idD + '_roundCheckboxWidget">';
    html += '<input   id="' + idD + '_chckBox" class="" type="checkbox" tid="" title="discard">';
    html += '<label id="' + idD + '_chckBox_label" for="' + msgItem.title + '" ></label> ';
    html += "&nbsp;" + msgItem.title;
    html += '</div>';
    html += '</div>';
    html += '';
  });
  html += '</div>';
  $('#demo').html(html);
  if(data[data.length - 1]) return false;
  
  $.each(data, function(index, element) {
    var idD = element.title + index;
    const self = this;
    if(index === data.length - 1) return false;
    $(document).on('click', '#' + idD + '_chckBox_label', (e) => {
      if (e.target.tagName === "LABEL") {
        e.preventDefault();
        e.stopPropagation();
        //console.log('#' + idD + '_chckBox_label');
        getdata(idD + '_chckBox');
      }
    });
    
  });
  data[data.length -1] = true;
}

function getdata(id) {
  //console.log(id);
  $("#" + id).prop("checked", !$("#" + id).prop("checked"));
  return true;
}
.roundCheckboxWidget {
  position: relative;
}

.roundCheckboxWidget label {
  background-color: #ffffff;
  border: 1px solid rgb(196, 196, 209);
  border-radius: 50%;
  cursor: pointer;
  height: 22px;
  left: 0;
  position: absolute;
  top: 0;
  width: 22px;
}

.roundCheckboxWidget label:after {
  border: 2px solid #fff;
  border-top: none;
  border-right: none;
  content: "";
  height: 6px;
  left: 4px;
  opacity: 0;
  position: absolute;
  top: 6px;
  transform: rotate(-45deg);
  width: 12px;
}

.roundCheckboxWidget input[type="checkbox"] {
  visibility: hidden;
}

.roundCheckboxWidget input[type="checkbox"]:checked+label {
  /* background-color: #6168e7 !important;
      border-color: 1px solid #6168e7 !important; */
}

.roundCheckboxWidget input[type="checkbox"]:checked+label:after {
  opacity: 1;
}

.roundCheckboxWidget input[type="checkbox"]:checked+label {
  background-color: #ff5b6a;
  border-color: #ff5b6a !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p>Alternate click on two buttons without refreshing causing getdata() method call twice. </p>

<button id="btn11">Try It</button>
<button id="btn00">Try It2</button>
<div id="demo"></div>
like image 26
Maheer Ali Avatar answered Sep 20 '22 21:09

Maheer Ali