我正在尝试创建具有从API中提取的子类别的<optgroup>
。目前,只有<optgroup>
正在填充,但没有填充子类别。
let select = document.querySelector("#category");
const categoriesURL = "INSERT_URL"
let str = "";
fetch(categoriesURL)
.then(response => response.json())
.then(data => {
data.forEach(category => {
let categoryTitle = category.title;
str += `<optgroup label=${categoryTitle}></optgroup>`
category.subcategories.forEach(sub => {
let subcategories_id = sub.subcategories_id;
let subcategoriesURL = `INSERT_URL/${subcategories_id}`;
fetch(subcategoriesURL)
.then(response => response.json())
.then(subData => {
str += `<option value=${sub.subcategories_id}>` + subData.title + "</option>";
})
})
})
select.innerHTML = "<option disabled selected>Select a category</option>" + str;
});
在字符串中定义optgroup
时,您可以立即打开和关闭optgroup,有效地将每个选项都放在optgroup之后。
str += `<optgroup label=${categoryTitle}></optgroup>`
使上述字符串中的optgroup
保持打开状态。
然而,困难的部分是在子类别上的所有fetch
请求完成后关闭字符串。我们可以用Promise.all
和Array#map
来实现这一点。
使用map
循环所有子类别,并返回fetch
在循环中返回的Promise
。当完成所有fetch
请求时,代码将继续到Promise.all
函数之后的then
块。在该块中,您将在一个数组中收集所有子类别的id和标题。在数组上循环以附加到字符串。
循环结束后,关闭optgroup
元素。
fetch(categoriesURL)
.then(response => response.json())
.then(data => {
data.forEach(category => {
let categoryTitle = category.title;
str += `<optgroup label=${categoryTitle}>`;
Promise.all(category.subcategories.map(sub => {
let subcategories_id = sub.subcategories_id;
let subcategoriesURL = `INSERT_URL/${subcategories_id}`;
return fetch(subcategoriesURL)
.then(response => response.json())
.then(({ title }) => ({
title,
id: subcategories_id
}))
})).then(subData => {
subData.forEach(({ id, title }) => {
str += `<option value=${id}>${title}</option>`;
})
str += '</optgroup>';
});
})
select.innerHTML = "<option disabled selected>Select a category</option>" + str;
});
不过,总的来说,这是一个非常昂贵的脚本,因为它会创建大量请求。如果你对后端有任何发言权,那么我建议你在一个请求中发回所有数据,并根据结果创建列表。