1

I need to check a radio button when the user clicks anywhere in the parent li. The ul is in the original html but the li and radio button are rendered to the DOM in a for loop inside a function below (displaySearchResults(responseJson).

Have not been able to apply any change to the radio button for the specific clicked li (sometimes able to change all radio buttons) -- no luck using the this keyword or various class/id/element combinations to target children of the clicked li.

Here is the event listener followed by relevant code.

This has been an absolute nightmare, any help is appreciated. Thanks!

EVENT LISTENER

function select(){
$('.results-list-item').click(event => { 
let name = $(this)
console.log('li click')
//various attempts at marking the child radio button as checked 
//$(this).closest($('input')).prop("checked", true)
//$(this).children($('input')).attr('checked','true')
$('.results-list-item').children($('input.radio')).attr('checked','')
 }) 
};

DISPLAY

function displaySearchResults(responseJson) { 
    for (let i = 0; i < 10; i++){
      $('#results-list').append(
      `
      <li class='results-list-item'>
      <h3>${results[i].name}</h3> 
      <input type='radio' id='${results[i].name}' value='${responseJson.results[i].id}' required>
     </li> 
     `
      )
    }
  select()
}

HTML

<main class='container'>
<section id='results'>
<form id='js-results-form'>
<ul id='results-list'>
</ul>
<input type='submit' value='Select Game'></input>
</form>
</section>
</main>
Jonas
  • 121,568
  • 97
  • 310
  • 388
dkburd
  • 1
  • 4
  • THANK YOU! switching to .on() solved this problem. It was previously solved on stack overflow but I just didn't realize how to find the answer. – dkburd Mar 13 '21 at 23:10

2 Answers2

1

Tl;Dr::

  1. You don't need any JS click listener, simply use a <label> as wrapper.
  2. PS: $collection.click() will work only for already present (on DOM ready) Elements. Your elements are generated dynamically: therefore use the .on() Method: $staticParent.on("eventName", "dynamicChild", fn)

Ok;Wr::

  1. Remove totally your functionSelect()
  2. Instead use the jQuery .on() method with delegated event handlers in order to assigning a listener to the static parent element for an event that was triggered from a specific present or future element target.
  3. Use ev.preventDefault(); inside the handler to prevent the label or checkbox/ or radio firing back
  4. What to make your LI clickable?? You don't have to, simply use the HTML <label> element and set it in CSS as display: block;
// How it works:
// "Static parent" on "evtName"  "dynamic child"    
$('#results-list').on("click", ".results-list-item", function(ev) {
  console.log(this);               // The LI Element
  console.log(ev.currentTarget);   // The LI element
  console.log(ev.delegateTarget);  // The static UL Element  
  console.log(ev.target);          // Some Element dispatcher, who knows...
});

Further more, for displaying the LIs results:

// Elements

const $resultsList = $('#results-list');

// Templates

const tpl_item = (item) => `<li class='results-list-item'>
  <label>
    <span>${item.name}</span>
    <input type="checkbox" name="${item.name}" value="${item.id}" required>
  </label>
</li>`;

// UI

const UI_displaySearchResults = (responseJson) => {
  const html_listItems = responseJson.reduce((s, item) => s + tpl_item(item), "");
  $resultsList.append(html_listItems);
};

// Events

$resultsList.on("click", "li", function(ev) {
  ev.preventDefault(); // Prevent label (input) firing twice
  console.log(this.textContent.trim()); // The LI element content, if needed?
});

// Finally: on Init or on AJAX request, does not matters any more:

UI_displaySearchResults([
  {id: 4, name: "Lorem ipsum"},
  {id: 9, name: "Dolor dolor, dolor"},
  {id: 8, name: "Sit amet"},
]);
#results-list label {
  display: block;
}

li:hover {
  background: gold; /* demo only */
}
<ul id="results-list"></ul>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
-1

I take a look on your problem and maybe you could solve it just with HTML, assuming that the input will have a text on it you could add a tag and using a prop "for" to link the text to the input

I also took the opportunity to correct a detail that you ended up missing, when you are calling ${results[i].name} the responseJson is missing Like the following example:

$('#results-list').append(
    `
    <li class='results-list-item'>
        <h3>${responseJson.results[i].name}</h3> 
        <label for='${responseJson.results[i].id}'>
            <input type='radio' id='${responseJson.results[i].id}' value='${responseJson.results[i].name}' required>
            ${responseJson.results[i].name}
        </label>
    </li>
    `
)

I hope have helped!