我正在尝试构建一个下拉列表,其中包含我需要访问的子级和孙级别对象,这些对象未包含在ajax调用的初始响应中。
我正在使用此结构进行级联ajax调用:
$.ajax({
url:"../../api/getEnum",
data: {itemFilter: "", Id: "~some guid~"},
dataType: "json",
success: function(data){
var dropdownObject = [];
dropdownObject.push('<option value=""></option>');
$(data).each(function(){
//optgroup level
if($(this)[0].HasChildren == true){
dropdownObject.push('<optgroup label="' + $(this)[0].Text + '">');
$.ajax({
url:"../../api/getEnum",
data: {itemFilter: "", Id: $(this)[0].Id},
dataType: "json",
success: function(data){
$(data).each(function(){
//prepend level
if($(this)[0].HasChildren == true){
var prependage = $(this)[0].Text;
$.ajax({
url:"../../api/getEnum",
data: {itemFilter: "", Id: $(this)[0].Id},
dataType: "json",
success: function(data){
$(data).each(function(){
dropdownObject.push('<option value="' + $(this)[0].Id +'">' + prependage + ": " + $(this)[0].Text + '</option>');
})
}
})
}
})
}
})
dropdownObject.push('</optgroup>');
}
else {
dropdownObject.push('<option value="' + $(this)[0].Id +'">' + $(this)[0].Text + '</option>');
}
});
$('#dropDown').html(dropdownObject.join(''));
$("#dropDown").trigger("chosen:updated"); //needs to be done to trigger the update of my drop down with "Chosen plugin" after all options have been built.
}
})
&#13;
以下是我正在使用的数据结果示例:
...{Id: "~some guid~", Text: "Medium", Name: "Medium", HasChildren: true,…}...
因此,如果HasChildren为真,我需要根据父级的GUID级联对API的新调用。由于AJAX的异步性,我认为,UI只是构建没有孩子的最高级别选项。为了表现,我不想关闭异步,但我不知道如何在正确的时间以正确的顺序获得我的回复。
我想我可能需要构建一个回调函数来处理排序,然后在结束时执行更新触发器,但我没有太多经验,我不确定这是正确的方向。
感谢您的帮助!
答案 0 :(得分:-1)
首先,有两个我不理解的陈述(第7-8行):
var areaOption = [];
dropdownObject.push('<option value=""></option>');
也许第一个在其他地方很有用,所以没关系(尽管你最好把它放在success:
函数之外)。
但我不知道第二个人是如何合法的。
源数据结构。
关于嵌套级别,我很惊讶你有3个级别,而似乎只有2级可以完成这项工作。当孩子存在时,你会建立这样的东西:
<optgroup label="level-1-text">
<option value="level-3-id">Level-2 text: Level-3 text</option>
</optgroup>
其中第二级仅 以获得&#34; Level-2文本&#34;。
因此,示意性地显示相应的源结构是这样的:
calling Id: "~some guid~"
returns {Id: "level-1-id", Text: "Level-1 text", HasChildren: true}
>>> <optgroup label="level-1-text">
calling Id: "level-1-id"
returns {Id: "level-2-id", Text: "Level-2 text", HasChildren: true}
>>> (nothing)
calling Id: "level-2-id"
returns {Id: "level-3-id", Text: "Level-3 text", HasChildren: false}
>>> <option value="level-3-id">Level-2 text: Level-3 text</option>
因此,如果你掌握了源数据结构,最好使用这样的东西:
calling Id: "~some guid~"
returns {Id: "level-1-id", Text: "Level-1 text", HasChildren: "Level-2 text"}
>>> <optgroup label="level-1-text">
calling Id: "level-1-id"
returns {Id: "level-3-id", Text: "Level-3 text", HasChildren: false}
>>> <option value="level-3-id">Level-2 text: Level-3 text</option>
注意:这里我保持了&#34; level-2&#34;和&#34; 3级&#34;名称是一致的,而现在只有2个级别。
使用jQuery。
我很惊讶你用$(data).each(function()
迭代收到的JSON数组:这个表单用于处理jQuery对象,而对于数组和其他非jQuery对象,我们应该使用$.each(data, function()
所以我进行了一些测试并且惊讶地发现它也有效,尽管它不应该!您可以在the question I posted about that中找到详细调查结果。
另一点是你解决上面迭代传递的每个项目的方式:$(this)[0].HasChildren
不必要地复杂化,因为它先后将this
封装在一个jQuery对象中,然后将其解压缩!
您应该只使用this.HasChildren
。
建议实现整个工作的简单方法。
将HTML构建为字符串的线性变化并非易事,因为:
<optgroup>
的结束标记必须在创建内部<option>
后出现相反,在需要时,可以轻松使用jQuery依次构建<option>
和<optgroup>
。
请注意,这意味着我们必须使用jQuery.append()
代替jQuery.html()
来执行此操作。
关于源数据的嵌套方面,最简单的方法是使用递归而不是在嵌套级别中多次使用$.ajax
。
它还具有减少代码并使其更具可读性的优势。
以下是基于上述所有考虑因素的片段
请注意,我还根据我之前的建议对其进行了简化,仅使用HasChildren
(为了清晰起见,重命名为Children
)来提供有关嵌套<optgroup>
的信息。对于<option>
,它甚至不必存在。
function buildMenu(Id, $parent, prependage) {
$parent = $parent || $('#dropdown');
$.ajax({
url:"../../api/getEnum",
data: {itemFilter: "", Id: Id},
dataType: "json",
success: function(data) {
$.each(data, function() {
if (!this.Children) {
// create a simple <option>
$parent.append('\
<option value="' + this.Id + '">\
' + (!!prependage ? (prependage + ': ') : '') + this.Text + '\
</option>\
');
} else {
// create an <optgroup>
$parent.append('\
<optgroup label="' + this.Text + '">\
</optgroup>\
');
// call for <option>s in this optgroup
buildMenu(this.Id, $('optgroup:last', $parent), this.Children);
}
});
}
})
}
buildMenu('~some guid~');
可以肯定的是,我测试了一个稍微修改过的版本,您可以尝试检查它是否按预期工作:
<?php
$menus = [
'~some guid~' => [
["Id" => "level-1-1", "Text" => "Text-1-1"],
["Id" => "level-1-2", "Text" => "Text-1-2"],
["Id" => "level-1-3", "Text" => "Text-1-3", "Children" => "level-1-3"],
["Id" => "level-1-4", "Text" => "Text-1-4"],
["Id" => "level-1-5", "Text" => "Text-1-5", "Children" => "level-1-5"],
],
'level-1-3' => [
["Id" => "level-1-3-1", "Text" => "Text-1-3-1"],
["Id" => "level-1-3-2", "Text" => "Text-1-3-2"],
["Id" => "level-1-3-3", "Text" => "Text-1-3-3"],
],
'level-1-5' => [
["Id" => "level-1-5-1", "Text" => "Text-1-5-1"],
["Id" => "level-1-5-2", "Text" => "Text-1-5-2"],
["Id" => "level-1-5-3", "Text" => "Text-1-5-3"],
],
];
if ($Id = @$_REQUEST['Id']) {
echo json_encode($menus[$Id]);
exit;
}
?>
<select id="dropdown">
</select>
<script src="http://code.jquery.com/jquery-1.11.3.js"></script>
<script>
function buildMenu(Id, $parent, prependage) {
$parent = $parent || $('#dropdown');
$.ajax({
url:'',
data: {itemFilter: "", Id: Id},
dataType: "json",
success: function(data) {
$.each(data, function() {
if (!this.Children) {
// create a simple <option>
$parent.append('\
<option value="' + this.Id + '">\
' + (!!prependage ? (prependage + ': ') : '') + this.Text + '\
</option>\
');
} else {
// create an <optgroup>
$parent.append('\
<optgroup label="' + this.Text + '">\
</optgroup>\
');
// call for <option>s in this optgroup
buildMenu(this.Id, $('optgroup:last', $parent), this.Children);
}
});
}
});
}
buildMenu('~some guid~');
</script>