Checkbox inputs with activated labels causing double events to fire

Creating round checkboxes with tick marks dynamically and appending them to id="demo" on the click of two buttons that invoke the get(data) method is my current goal.

The issue arises when both buttons are clicked simultaneously, as the checkboxes do not get checked and it leads to multiple calls to the getdata(idD + '_chckBox') method, which can be observed in the console.log.

Despite using

e.preventDefault(); e.stopPropagation();
, the problem persists.

Why is the getdata(idD + '_chckBox') method called multiple times and the round checkbox remains unchecked?

I am attempting to toggle the checkbox and display the tick mark. Any suggestions for a better approach are welcome.

What is the most efficient way to bind the onclick and onscroll methods in dynamic HTML elements within a loop so that an object can be passed as a parameter to the invoked method onclick?

index.html

   
     var data0 = [{
            "title": "a"
          },
          {
            "title": "b"
          },
          {
            "title": "c"

............

Answer №1

Here are a few mistakes that need to be addressed:

  1. The usage of non-unique IDs is prevalent in the code, leading to duplicated IDs being generated on button clicks. A counter should be implemented for uniqueness.
  2. There seems to be a misunderstanding of event delegation with the use of an .each() loop to define delegated event handlers.
  3. The function used to toggle the checkbox state can be simplified by utilizing the for= attribute on the label.
  4. The functionality of the loadMoreContent() function is unclear; it might be intended for infinite scrolling, but precautions should be taken to prevent excessive Ajax requests on scroll events.

To address these issues, follow this approach:
   (Refer to the comments within the code)

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

// Append the "parent" div upon loading.
var html = "<div id='parent'></div>";
$(html).appendTo('body');

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

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

// Main function requiring a counter for unique ID generation.
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);
}

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

// Scroll event handler to check if bottom of page is reached for content loading
$(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 more!");
    
    // Trigger 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: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 Link

Answer №2

Here are a couple of issues with the code:

  • You have both onclick="get()" and a click event using jQuery, which results in triggering the function twice. Remove onclick ="get()"
  • The second issue is that every time get() is called, it adds new click listeners to checkboxes. To avoid this, use a boolean value in your array to apply the click event only 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>Clicking alternatively on two buttons without refreshing causes the getdata() method to be called twice.</p>

<button id="btn11">Try It</button>
<button id="btn00">Try It2</button>
<div id="demo"></div>

Answer №3

Summary

Prior to binding a new event handler, make sure to unbind the existing ones. You can achieve this by using the following code snippet:

$(document).off('click', '#' + idD + '_chckBox_label').on('click', '#' + idD + '_chckBox_label', (e) => {

Detailed Explanation

Using

e.preventDefault(); e.stopPropagation();
won't prevent multiple function calls. The key is to eliminate previous event handlers before setting up a new one.

Consider a scenario where you attach event handlers to an element twice - both will get executed irrespective of user interaction.

The solution lies in "removing the current click handler prior to adding a fresh one".

This line:

$(document).on('click', '#' + idD + '_chckBox_label', (e) => {
binds an event handler to a label. However, on subsequent button clicks, it appends another handler, leading to duplicated functionality.

Each click operation adds a new event handler to the element.

Refreshing the page resolves the issue as it wipes out all existing handlers. To address this programmatically, follow these steps.

$(document).off('click', '#' + idD + '_chckBox_label').on('click', '#' + idD + '_chckBox_label', (e) => {

This piece of code instructs the system to deactivate any prior click handlers and install a fresh one.

Additional Tip:

If your functions are named, you can selectively remove specific event handlers like so:

$(document).off(<event_type>, <el_selector>, <event_handler>).on(<event_type>, <el_selector>, <event_handler>);

I hope this clarifies things. Feel free to reach out if you have further questions.

Note: I may have encountered some typos while copying and pasting the code, but the primary focus here is not running the code :)

Answer №4

Within this section, you are utilizing 2 click event listeners:

$(document).on('click', '#btn11', () => {
  fetch(data0);
})
$(document).on('click', '#btn00', () => {
  fetch(data1);
})

Your fetch() function includes two $.each() loops. The second loop introduces an additional event listener:

$(document).on('click', '#' + idD + '_chckBox_label', (e) => {
  if (e.target.tagName === "LABEL") {
    e.preventDefault();
    e.stopPropagation();
    console.log('#' + idD + '_chckBox_label');
    retrieveData(idD + '_chckBox');
  }
});

Upon clicking the second button, it appears that there may be a total of 3 event listeners listening for that specific event.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing Jquery to retrieve an array as the return value from a $.post request

After going through numerous discussions on this topic, I'm still struggling to make it work. However, I've made significant progress. I have a scenario where I send data from jQuery to my database. The database returns a record consisting of two ...

Finding the best way to transfer text between DIV elements?

I have a dilemma involving two DIV elements positioned absolutely on the sides of an HTML page, much like this EXAMPLE: <div class="left"> </div> <div class="right"> </div> These are styled using the following CSS: .left{ pos ...

What is the best way to manage the back button functionality on pages that use templates?

I am currently developing a website using angularjs. The layout consists of two main sections: the menu and the content area. For instance This is an example page: /mainpage <div> <div id="menu"> <div ng-click="setTemplate('fi ...

Creating a Custom Form Control in Angular 2 and Implementing Disable Feature

I have developed a unique custom control using ControlValueAccessor that combines an input[type=text] with a datepicker. While the template-driven forms accept it without any issues, the situation changes when implementing the model-driven approach (react ...

Prompt for confirmation in ASP.NET code-behind with conditions

I've searched around for a solution to this problem. Below is a representation of my pseudocode: bool hasData = ItemHasData(itemid); Confirm = "false"; // hidden variable if (hasData) { //Code to call confirm(message) returns "true" or "false" ...

Passing multiple parameters in URL for APIs using Next.js

Is there a way to pass multiple parameters and retrieve results from the next.js API? I found the documentation very helpful, you can check it out here /api/posts/[postId].js The above setup works fine, but I want to know if it's possible to pass an ...

Is It Always Necessary to Specify a Width and Height for an Image?

Is it necessary to specify both the Width and Height of an image on a webpage for consistent display across all browsers, or is specifying just one sufficient? While it may appear fine on certain browsers, I want to double-check for accuracy. Appreciate ...

Another return payload failing to retrieve the return value

I'm currently facing an issue where a function that should return a value is not being passed on to another function. Below is the code snippet in question: public _getProfileToUpdate() { return { corporateId: this.storeService.setStoreData().p ...

Leveraging jQuery to fetch the values of multiple checkboxes and displaying them as a string separated by commas

I have a variety of checkboxes listed below: <li><input type="checkbox" name="areaofinterest" value="home_coo" id="home_coo" class="Checkbox" > Cooking</li> <li><input type="checkbox" name="areaofinterest" value="home_cra" i ...

The type 'string | undefined' cannot be assigned to type 'string'

I am facing a challenge in comparing two arrays, where one array is sourced from a third-party AWS service and its existence cannot be guaranteed. Despite my efforts to handle potential errors by incorporating return statements in my function calls, I con ...

Bidirectional updates in AngularJS with CSS styling

On the backend, certain HTML elements store their position and size persistently and retrieve them when the page loads. These elements can be dragged and resized by users, with any updates needing to be saved on the backend for consistency across sessions. ...

I am experiencing an issue where the Laravel URL is not being passed to the controller

In my project, I am utilizing ajax along with Laravel 5.4. The issue I am facing is that when the ajax function is executed, it successfully returns the email but does not display the URL page in the console window. Here is the code for the Ajax function: ...

Need to monitor a Firebase table for any updates

How can I ensure my Angular 2 app listens to changes in a Firebase table? I am using Angular2, Firebase, and TypeScript, but the listener is not firing when the database table is updated. I want the listener to always trigger whenever there are updates or ...

Is there a way for me to produce a random choice depending on the option selected by the user in the <select> menu?

As a beginner in JavaScript, I am attempting to create a feature where users can select a genre from a dropdown list and receive a random recommendation from that genre displayed on the screen. In essence, my goal is to allow users to get a random suggest ...

Error: Webpack encountering reference errors when handling multiple entry points

Here is my setup in webpack.config.js: entry: { a:'./src/a.js', b:'./src/b.js' }, output: { path: path.join(__dirname, 'dist'), filename: '[name].bundle.js' } The content of a.js includes: const ...

Guide on crafting a side navigation menu that mimics the sleek functionality of mobile applications

Looking to develop a web app and mobile app hybrid, I started using bootstrap, jQuery, and Vuejs. Now, I aim to create a navigation menu that slides in from the left or right, similar to what we see in many mobile applications. To achieve this, I explored ...

SignalR gets stuck on the 'Initiating start request' screen, halting all progress

SignalR has been causing some strange behavior for me lately. After doing some refactoring, I started experiencing connectivity issues. It seems like my code was just lucky to work before because it didn't follow the recommended practices. For example ...

Press the button to eliminate

Is there a way for users to add tags by typing text and then clicking on an add button? Once the tag is added, it appears with a delete button, allowing users to manage their list of tags. The JavaScript code below enables users to add tags successfully, ...

Keeping the color of CSS buttons consistent can be achieved by setting specific

Here is my CSS code: .horizontalcssmenu ul{ margin: 0; padding: 0; list-style-type: none; list-style:none; } .horizontalcssmenu ul a:active{ color: #00FFFF; background: #FF0033; text-decoration: none; } /* Styles for top leve ...

I'm having trouble with jQuery recognizing the left-margin property. Is there a workaround for this issue?

I rarely use jquery, but I wanted to add animation to a side bar. The sidebar menu is 670px with a -670 left-margin. When the user hovers over it, I'd like the left-margin to change to 0px and reveal the hidden content. Upon mouseout, it should return ...