Mark Dungey
Mark Dungey

Reputation: 13

HTML select not refreshing after being populated via JQuery

I've been using JQuery to populate a drop down list on the click of a HTML select element. The options get created however on the first click the options get shown in a very small box with a scroll. see below

incorrect

If I then close and reopen the dropdown it appears correctly. as below.

correct

It feels like the dropdown list is appearing before jquery has rendered the new options elements. I've tried to find away to re-render it but with no luck.

This feels like it should be such an easy fix but I'm new to scripting and struggling.

HTML

<select class="custom-select" id="templateGroupName" name="templateGroupName">
    <option selected>Please Select a group</option>
</select>

JS - Wrapped in document.ready

$('#templateGroupName').click(function () {
    $.ajax({
        type: "GET",
        url: '/Layout/GetGroups',
        success: function (data) {
            helpers.buildDropdown(
                data,
                $('#templateGroupName'),
                'Select an option'
            );
        }
    });

});

var helpers =
{
    buildDropdown: function (result, dropdown, emptyMessage) {
        // Remove current options
        dropdown.html('');
        // Add the empty option with the empty message
        dropdown.append('<option value="">' + emptyMessage + '</option>');
        // Check result isnt empty
        if (result != '') {
            // Loop through each of the results and append the option to the dropdown
            $.each(result, function (k, v) {
                dropdown.append('<option value="' + v.Id + '">' + v.Name + '</option>');
            });
        }
    }
}

Upvotes: 0

Views: 1001

Answers (2)

mccallofthewild
mccallofthewild

Reputation: 520

The browser gets confused when you inject options while the <select> is open. To be fair, your users would probably be confused too.

If you're waiting for something to load, tell them to wait. If something isn't usable, disable it.

Putting these two together: the first time a user hovers over the <select>, disable it and set the cursor to a loading wheel. Wait until your data loads, then insert the options, re-enable it and switch the cursor back.

var helpers = {
  buildDropdown: function(result, dropdown, emptyMessage) {
    dropdown.html('');
    dropdown.append(`<option value="">${emptyMessage}</option>`);
    if (!!result) {
      $.each(result, function(k, v) {
        dropdown.append(`
            <option value="${v.Id}">
              ${v.Name}
            </option>
         `);
      });
    }
  }
}

const $DROPDOWN = $('#templateGroupName');
// using jQuery#one to only fire the click event once
$DROPDOWN.one('mouseenter', _ => {
  // disable dropdown while loading options
  $DROPDOWN.attr('disabled', true)
  console.log('loading options...');
  // replace contents with your GET request
  setTimeout(function() {
    helpers.buildDropdown(
      Array.from({
        length: 30
      }, (_, i) => ({
        Id: i,
        Name: i
      })),
      $DROPDOWN,
      'Select an option'
    );
    // un-disable after options are loaded and inserted
    $DROPDOWN.attr('disabled', false)
  }, 1000);
})
/* Show "loading" wheel while loading */

select.custom-select[disabled] {
  cursor: wait;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select class="custom-select" id="templateGroupName" name="templateGroupName">
  <option selected>Please Select a group</option>
</select>

Upvotes: 0

Diodeus - James MacFarlane
Diodeus - James MacFarlane

Reputation: 114367

First, you need a <select> as the parent, not an empty element,

dropdown = $('#templateGroupName');

then insert it as a document element, not a string:

var opt = document.createElement('option');
opt.value = v.Id;
opt.innerHTML = v.Name;
dropdown.appendChild(opt);

Upvotes: 1

Related Questions