No stupid questions
No stupid questions

Reputation: 485

jQuery: Dynamic click event only firing after second click

I have created a custom form that allows users to lookup a specific option by name instead of searching for it in a lengthy list--for a media browser. The code does what I want with one exception. Clicking on the dynamically added suggestions does not trigger the click event the first time you click on it.

Clicking anywhere else on the screen seems to reset this, then allowing me to be able to click on my option and select it. I'm not entirely sure why this is happening but based on the console output it seems like my code is getting stuck somewhere before being able to continue.

$(document).ready(function() {
  // Custom select form
  $('select.custom_select').each(function(i) {
    var select = $(this);
    var custom_input = select.next().children('input');
    var delete_selection = custom_input.next();
    var suggestion_list = delete_selection.next();

    // Set defaults in the custom form
    var selected = select.find(":selected");
    if (selected.index() != 0) {
      select.val(selected.val()).change();
      custom_input.val(selected.text())
      custom_input.attr('readonly', true);
      delete_selection.addClass('option_selected');
    }

    // User is typing in the custom form
    custom_input.on("change keyup paste", function() {
      suggestion_list.empty();
      console.log('suggestions cleared');
      suggestion_list.css('visibility', 'hidden');
      custom_input.removeClass('no_matches');

      var user_input = custom_input.val();
      if (user_input != '') {

        // Show options to the user
        select.children('option').each(function(i) {
          let option = $(this);
          var text = option.text();
          if (text.toLowerCase().includes(user_input.toLowerCase())) {
            var re = new RegExp('(' + user_input + ')', 'gi');
            suggestion_list.append(`<li data-value="${option.val()}" data-name="${text}">${text.replace(re, '<span>$1</span>')}</li>`);
            console.log('suggestion added');
          }
        });

        if (suggestion_list.children().length == 0) {
          custom_input.addClass('no_matches');
        } else if (!custom_input.attr('readonly')) {
          suggestion_list.css('visibility', 'visible');
          suggestion_list.focus();
        }
      }
    });

    // Choose an option
    suggestion_list.on('click', 'li', function() {
      select.val(parseInt($(this).attr('data-value'))).change();
      custom_input.val($(this).attr('data-name'))
      custom_input.attr('readonly', true);
      delete_selection.addClass('option_selected');
      suggestion_list.css('visibility', 'hidden');
    });

    // Reset the custom form
    delete_selection.on('click', function() {
      select.val('').change();
      custom_input.attr('readonly', false);
      delete_selection.removeClass('option_selected');
      suggestion_list.css('visibility', 'visible');
      custom_input.focus();
    });
  });
});
.delete_selection {
    display: none;
}

.option_selected {
    display: initial;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<p>Type in the input to get suggestions. Click on a list item to select it.</p>
<select class="custom_select" id="id_file" name="file">
    <option value="" selected="selected">---------</option>
    <option value="1">image.svg</option>
    <option value="2">video.mp4</option>
    <option value="3">game.iso</option>
</select>
<div class="custom_select_form">
  <input type="text" spellcheck="false">
  <i class="delete_selection" aria-hidden="true">X</i>
    <ul>
    </ul>
</div>

Upvotes: 1

Views: 191

Answers (1)

Jeto
Jeto

Reputation: 14927

Try replacing:

custom_input.on("change keyup paste", function() { ... });

with just:

custom_input.on("keyup paste", function() { ... });

Explanation: binding change will also trigger the event when you leave the filter input (when the focus is no longer on it). Since the corresponding handler uses/modifies the list of suggestions, your click event on them might be impacted.

Also note that input propertychange are the two events that are recommended to check for actual user input, as opposed to key* events. It would also trigger when the user pastes something. So you should do this:

custom_input.on('input propertychange', function() { ... });

Upvotes: 1

Related Questions