如何在“opt group elements”中动态嵌套“option elements”?

How do I dynamically nest “option elements” within “opt group elements”?

const url = "https://restcountries.eu/rest/v2/all"

  fetch(url)
  .then(function(response){
    return response.json()
  })
  .then(function(data){
    console.log(data)
    worldRegion(data)
  })


  function worldRegion(myData) {
    var myArray = []
    for(var i = 0; i < myData.length; i++) {
      myArray.push(myData[i].region)
    }
    var region = myArray.filter(onlyUnique);
    var regionOptgroup = ""
    for(var i = 0; i < region.length; i++) {
      regionOptgroup += `<optgroup value=${region[i]} label="${region[i]}">${region[i]}</optgroup>`
    }
    document.querySelector("select").innerHTML = regionOptgroup
    const nodeList = document.querySelectorAll("optgroup")

    console.log(nodeList)

    var options  = ""
    for(var i = 0; i < myData.length; i++) {

      for(var j = 0; j < nodeList.length; j++) {
        if(myData[i].region === nodeList[j].value)
        options += `<option value="${myData[i].name}">${myData[i].name}</option>`
      }

    }
    document.querySelector("select").innerHTML = options

  }

  function onlyUnique(value, index, self) {
    return self.indexOf(value) === index;
  }
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>what language do they speak</title>
  </head>
  <body>
    <select class="" name="">


    </select>

    <br>

  </body>
  <script src="index.js" type="text/javascript">

  </script>
</html>

我使用 for 循环创建了 6 个不同的 opt 组元素,即亚洲、欧洲、非洲、大洋洲、美洲和极地。然后我将有问题的 opt 组元素嵌套在 select 元素中。我还将 selection 元素或节点列表存储在名为 nodeList 的变量中。

我正在尝试复制或多或少类似的方法,以便根据国家所属的区域将选项元素嵌套在选项组元素中。因此,具有 InnerHTML Singapore 和“value = Asia”的选项元素将嵌套在 Asia 选项组元素中。依此类推 250 个选项元素。

我一直在尝试做的是提取每个 opt 组元素的值,以便相应地嵌套我的 option 元素。因此,我的 if 语句中的以下条件:(=myData[i].region === nodeList[j].value)。但是,控制台还会抛出以下错误:“index.js:34 Uncaught (in promise) TypeError: Cannot read 属性 'value' of undefined at worldRegion (index.js:34)在 index.js:10”

然后它变成了意大利面条式的代码。

我已尝试尽可能清楚地说明问题。但是,如果您需要进一步说明,请随时发表评论。

我知道我可能需要改进缩进和优雅,但首先我希望我的代码能够正常工作

const url = "https://restcountries.eu/rest/v2/all"

  fetch(url)
  .then(function(response){
    return response.json()
  })
  .then(function(data){
    console.log(data)
    worldRegion(data)
  })


  function worldRegion(myData) {
    var myArray = []
    for(var i = 0; i < myData.length; i++) {
      myArray.push(myData[i].region)
    }
    var region = myArray.filter(onlyUnique);
    var regionOptgroup = ""
    for(var i = 0; i < region.length; i++) {
      regionOptgroup += `<optgroup value=${region[i]} label="${region[i]}">${region[i]}</optgroup>`
    }
    document.querySelector("select").innerHTML = regionOptgroup
    const nodeList = document.querySelectorAll("optgroup")

    console.log(nodeList)

    var options  = ""
    for(var i = 0; i < myData.length; i++) {

      for(var j = 0; j < nodeList.length; j++) {
      }
      if(myData[i].region === nodeList[j].value)
      options += `<option value="${myData[i].name}">${myData[i].name}</option>`
    }
    document.querySelector("select").innerHTML = options

  }

  function onlyUnique(value, index, self) {
    return self.indexOf(value) === index;
  }
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>what language do they speak</title>
  </head>
  <body>
    <select class="" name="">


    </select>

    <br>

  </body>
  <script src="index.js" type="text/javascript">

  </script>
</html>

您可以使用 DOM 方法而不是 HTML 创建 optgroup 元素,这样您就可以立即获得对每个创建的元素的引用。将这些元素存储在由区域名称键入的 Map 中。

然后当您最终创建选项时,您可以在该地图中查找区域,以便检索对相应 optgroup 元素的引用:

const url = "https://restcountries.eu/rest/v2/all";

(async () => {
    const response = await fetch(url);
    const data = await response.json();
    let select = document.querySelector("select");
    // Create a map, keyed by region
    let regions = new Map(data.map(({region}) => [region, null]));
    // Assign an optgroup to each region in that map
    for (let region of regions.keys()) {
        let optgroup = document.createElement("optgroup");
        optgroup.setAttribute("value", region);
        optgroup.setAttribute("label", region || "(blank)");
        select.appendChild(optgroup);
        regions.set(region, optgroup);
    }
    for (let country of data) {
        // Create an option for each country
        let option = document.createElement("option");
        option.setAttribute("value", country.name);
        option.textContent = country.name;
        // Append it to the relevant optgroup
        regions.get(country.region).appendChild(option);
    }
})();
<select class="" name="">
</select>