Skip to content
Advertisement

Asynchronous loading of select list options

I’m retrieving information on Municipality names, ZipCodes, etc. from a public service provider (DAWA) using AJAX. At first I had an issue retriving the data until I made the transfer asyncronous, thus ajaxGetMunicipalitiesFromDAWA is an asyncronous function. I have checked ajaxGetMunicipalitiesFromDAWA and it loads data correctly.

The I try to update my selectlist using the data, but it seems the update occurs before Municipalies is loaded. I have tried to make loadMunicipalities asyncronous as well, but still I end up having an empty option list.

Please help

HTML code:

<div class="row mt-3 fw-bold">
    <div class="col-3"><label asp-for="PostalAddress_Municipality">Municipality:</label></div>
    <div class="col-9">
        <select asp-for="PostalAddress_MunicipalityId" class="form-control form-control-sm" name="municipality"></select>
    </div>
</div>

JavaScript:

    var Municipalities = ajaxGetMunicipalitiesFromDAWA();
    
async function ajaxGetMunicipalitiesFromDAWA() {
    var output = [];
    var xHttp = new XMLHttpRequest();
    xHttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            var dawaData = JSON.parse(this.responseText);
            dawaData.forEach(function (data) {
                output.push({ Id: data.kode, Name: data.navn, CountryId: 53, CountryText: "Danmark", RegionId: data.regionskode, RegionText: data.region.navn });
            });
        }
    }
    xHttp.open("GET", "https://dawa.aws.dk/kommuner", true);
    await xHttp.send();
    return output;
}

async function loadMunicipalities() {
    var select = document.querySelector("municipality");
    var data = await Municipalities;
    data.forEach(function (municipality) {
        var option = document.createElement("option");
        option.value = municipality.Id;
        option.text = municipality.Name;
        option.selected = select.value == municipality.Id;
        select.add(option);
    });
}

Advertisement

Answer

Couple of things, XMLHttpResquest.send does not return a promise. So awaiting send will just await for the an empty microtask to complete and not actually the request. What you’d want to do is just wrap the request in a Promise which will be handled by the async FSM. You also need to actually call loadMunicipalities so that the list is actually populated. Below is a working example.

var Municipalities = ajaxGetMunicipalitiesFromDAWA();

async function ajaxGetMunicipalitiesFromDAWA() {
  var output = [];
  var xHttp = new XMLHttpRequest();
  return new Promise((resolve) => {
    xHttp.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        var dawaData = JSON.parse(this.responseText);

        dawaData.forEach(function(data) {
          output.push({
            Id: data.kode,
            Name: data.navn,
            CountryId: 53,
            CountryText: "Danmark",
            RegionId: data.regionskode,
            RegionText: data.region.navn
          });
        });

        resolve(output);
      }
    }
    xHttp.open("GET", "https://dawa.aws.dk/kommuner", true);
    xHttp.send();
  });

}

async function loadMunicipalities() {
  var select = document.querySelector("#municipality");
  var data = await Municipalities;

  data.forEach(function(municipality) {
    var option = document.createElement("option");
    option.value = municipality.Id;
    option.text = municipality.Name;
    option.selected = select.value == municipality.Id;
    select.add(option);
  });
}

loadMunicipalities();
<select id="municipality"></select>

So this works as is, but since you are using semi modern apis, id recommend that you use fetch as it handles almost all the fixes applied but makes the code much less verbose.

const requestMunicipalitiesFromDAWA = async() => {
  const response = await fetch("https://dawa.aws.dk/kommuner");
  const data = await response.json();
  
  return data.map((datum) => ({
    Id: datum.kode,
    Name: datum.navn,
    CountryId: 53,
    CountryText: "Danmark",
    RegionId: datum.regionskode,
    RegionText: datum.region.navn
  }));
};

const populateMunicipalitiesOptions = (data) => {
  var select = document.querySelector("#municipality");
 
  data.forEach(function(municipality) {
    var option = document.createElement("option");
    option.value = municipality.Id;
    option.text = municipality.Name;
    option.selected = select.value == municipality.Id;
    select.add(option);
  });
};

requestMunicipalitiesFromDAWA().then(populateMunicipalitiesOptions);
<select id="municipality"></select>
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement