Unable to Detect Change on Dynamically Generated Checkboxes

56 Views Asked by At

Description:

I'm facing an issue where dynamically generated checkboxes are not triggering the change event when clicked. To address this, I used $(document).on("change", ".integration-event-checkbox", ...) for event delegation. While this successfully attaches the event, I'm encountering a problem when attempting to retrieve checked checkboxes and update the URL dynamically.

Below is a simplified ( replica not the actual code) version of the code: HTML File (index.html):

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Multiple Choice Question with URL</title>
</head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
<body>

  <h2>Which events would you like to include in the URL?</h2>

  <form id="checkboxes">
    <label>
      <input type="checkbox" name="optionA" value="A" > A
    </label>
    <br>

    <label>
      <input type="checkbox" name="optionB" value="B" > B
    </label>
    <br>

    <label>
      <input type="checkbox" name="optionC" value="C" > C
    </label>
    <br>

    <label>
      <input type="checkbox" name="optionD" value="D" > D
    </label>
    <br>

    <label for="url">URL:</label>
    <input type="text" id="url" name="url" value="xyz.com" readonly>
  </form>

 <script src="script.js"></script>

</body>
</html>

JavaScript File (script.js):

$(document).ready(function() {
    const $checkboxes = $("#checkboxes");
    const integration = [ {all:["push","pull"]},{all:["post","get"]},{all:["put","delete"]}]
    const $eventCheckboxes = $(".integration-event-checkbox");

    // This event handler is not being triggered for dynamically generated checkboxes
    // $(document).on("change", ".integration-event-checkbox", (e) => {
    //     console.warn("Checkbox changed");
    //     console.warn("event",e);
    //     update_url();
    //     e.preventDefault();
    //     e.stopPropagation();
    // });

    const events = display_box(integration[0].all)
    $checkboxes.html(events);

    function display_box(integration){
      const checkboxesHTML = integration.map(item => `
          <label>
              <input type="checkbox" class="integration-event-checkbox" value="${item}" />
              ${item}
          </label>
      `).join('');

          return checkboxesHTML;
    }

    function update_url() {
        const selectedEvents = $eventCheckboxes.filter(":checked").map(function () {
            return this.value;
        }).get().join(",");
        console.log("SELECTED EVENTS: ", selectedEvents);
        // Add the checked events to the URL
        const eventsParam = selectedEvents.length > 0 ? `&events=${selectedEvents}` : '';
        console.log("Events Param: ", eventsParam);

        console.log("event checkboxes: ", $eventCheckboxes);
    }
});

Issue Details:

  1. The $(document).on("change", ".integration-event-checkbox", ...) event handler is not capturing changes for dynamically generated checkboxes.
  2. When attempting to retrieve checked checkboxes using $eventCheckboxes.filter(":checked").map(...), both selectedEvents and the $eventCheckboxes collection are empty.

Steps to Reproduce:

  1. Dynamically generate checkboxes using JavaScript.
  2. Attach a change event using $(document).on("change", ".integration-event-checkbox", ...).
  3. Click on dynamically generated checkboxes and observe the lack of change event triggering.
  4. Attempt to retrieve checked checkboxes using $eventCheckboxes.filter(":checked").map(...) and notice that the result is empty.

Expected Behavior:

The change event should be triggered for dynamically generated checkboxes, and the code should correctly retrieve and display the checked checkboxes.

I attempted to address the issue by reinitializing the $iec variable using let instead of const. I experimented with shifting the code above and below the point of reinitialization, aiming to ensure that the variable captures dynamically generated checkboxes properly.

Expected Behavior:

The change event should be triggered for dynamically generated checkboxes, and the code should correctly retrieve and display the checked checkboxes.

3

There are 3 best solutions below

0
Lee On

You can fix it by changing:

const selectedEvents = $eventCheckboxes.filter(":checked").map(function () {
  return this.value;
}).get().join(",");

To:

const selectedEvents = $(".integration-event-checkbox").filter(":checked").map(function () {
  return this.value;
}).get().join(",");

The $eventCheckboxes variable just doesn't have the dynamically added checkboxes yet at the point of initialization.

0
mark_dot On

instead of using this

const $eventCheckboxes = $(".integration-event-checkbox");

jQuery selector to a variable just use

$(".integration-event-checkbox").filter(":checked")...

when you declare this on top of the code with const when you call update_url() it doesn't contain the dynamically added checkboxes.

and my sugesstion is to get the checked cheboxes as follow

function update_url(){
  selected = new Array();
   $(".integration-event-checkbox").each(function(){
    if ($(this).is(':checked')) selected.push($(this).val())
   })
  let eventParams = new URLSearchParams({ someOtherParam: "test", events: selected.toString(),}).toString()
  console.log(eventParams)
}
0
chrwahl On

If you use the FormData() constructor you get only the relevant values from the form. If you filter that list for the entries named "event" you have the values.

const integration = [{
  all: ["push", "pull"]
}, {
  all: ["post", "get"]
}, {
  all: ["put", "delete"]
}];

document.addEventListener('DOMContentLoaded', e => {
  let form = document.forms.form01;
  form.addEventListener('change', update_url);

  form.checkboxes.innerHTML = display_box(integration[0].all);
});

function display_box(integration) {
  const checkboxesHTML = integration.map(item => `
          <label>
              <input type="checkbox" name="event" class="integration-event-checkbox" value="${item}" />
              ${item}
          </label>
      `).join('');

  return checkboxesHTML;
}

function update_url(e) {
  let form = e.target.form;
  let formdata = new FormData(form);
  let selectedEvents = [...formdata]
                          .filter(entry => entry[0] == 'event')
                          .flatMap(event => event[1]).join(',');
  console.log("SELECTED EVENTS: ", selectedEvents);
  let url = new URL(form.url.value);
  let params = new URLSearchParams(url.search);
  params.set('events', selectedEvents);
  form.url.value = url.origin + url.pathname + '?' + params.toString();
}
fieldset {
  border: none;
}
<h2>Which events would you like to include in the URL?</h2>

<form name="form01">
  <fieldset name="checkboxes">
    <label>
      <input type="checkbox" name="optionA" value="A" > A
    </label>
    <br>
    <label>
      <input type="checkbox" name="optionB" value="B" > B
    </label>
    <br>
    <label>
      <input type="checkbox" name="optionC" value="C" > C
    </label>
    <br>
    <label>
      <input type="checkbox" name="optionD" value="D" > D
    </label>
  </fieldset>
  <br>
  <label for="url">URL:</label>
  <input type="text" id="url" name="url" value="https://example.com" readonly>
</form>