级联AJAX响应以访问具有"hasChildren"的对象.不包含在JSON对象中的对象 [英] Cascading AJAX response to access objects that "hasChildren" that are not included in the JSON object
问题描述
我正在尝试构建一个下拉列表,其中包含我需要访问的子级和孙级对象,而这些对象未包含在ajax调用的初始响应中.
I am trying to build a dropdown that has child and grandchild level objects that i need to access that are not included in the initial response of an ajax call.
我正在使用这种结构来进行级联ajax调用:
I'm using this structure for my cascading ajax call:
$.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.
}
})
以下是我正在处理的数据结果的一个示例:
Here's an example of the data result that i'm working with:
...{Id: "~some guid~", Text: "Medium", Name: "Medium", HasChildren: true,…}...
因此,如果HasChildren为true,则需要根据父级的GUID级联对API的新调用.由于AJAX的异步性,我认为UI只是在构建没有子级的最高级选项.为了提高性能,我不想关闭异步,但是我不知道如何在正确的时间和正确的顺序获得响应.
So if HasChildren is true, I need to cascade a new call to the API against the GUID of the parent. Due to the asynchronicity of AJAX, I think, the UI is only building the upper most level options that have no children. For performance, I don't want to turn off async but I don't know how to get my responses at the right time and in the right sequence.
我认为我可能需要构建一个回调函数来处理排序,然后在此之后执行更新触发器,但是我对此没有太多经验,而且我不确定这是正确的方向.
I think I would probably need to build a callback function to handle the sequencing and then execute the update trigger at the end of that, but I don't have much experience with that and I'm not sure that's the right direction.
感谢您的帮助!
推荐答案
首先,有2条我不理解的语句(第7-8行):
First of all, there are 2 statements I don't understand (lines 7-8):
var areaOption = [];
dropdownObject.push('<option value=""></option>');
也许第一个在其他地方有用,所以没关系(尽管您最好将它放在success:
函数之外).
但是我不知道第二个可能是合法的.
Maybe the 1st one is useful elsewhere, so ok (though you'd probably better to put it outside of the success:
function).
But I don't figure out how the 2nd one might be legitimate.
源数据结构.
关于嵌套级别,我很惊讶您有3个级别,而似乎只有2个级别可以完成工作.当孩子存在时,您正在构建如下内容:
Regarding the nested levels, I'm surprised you have 3 levels, while it seems that only 2 could do the job. When children exist you're building something like this:
<optgroup label="level-1-text">
<option value="level-3-id">Level-2 text: Level-3 text</option>
</optgroup>
第二级仅对有用有用,以获取二级文本".
如此示意地表明,相应的源代码结构是这样的:
where the 2nd level is useful only to get "Level-2 text".
So schematically it appears that the corresponding source structure was like this:
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>
因此,如果您掌握了源数据结构,则最好使用如下所示的内容:
So if you have hand on the source data structure you'd better to use something like this:
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>
注意:这里为了保持一致性,我保留了"level-2"和"level-3"的名称,而现在只有2个级别.
jQuery的用法.
让您惊讶的是,您使用$(data).each(function()
迭代了接收到的JSON数组:这种形式旨在处理jQuery对象,而对于数组和其他非jQuery对象,我们应该使用$.each(data, function()
.
I was surprised you iterate the received JSON array with $(data).each(function()
: this form is intended to process jQuery objects, while for arrays and for other, not-jQuery, objects we are supposed to use $.each(data, function()
.
因此,我进行了一些测试,并惊讶地发现它也可以工作,尽管有时不应该!您可以在我对此发布的问题中找到详细的调查报告.
So I had some tests and was surprised to discover it works too, though it someway should not! You can find the detailed investigation reported in the question I posted about that.
另一点是解决上述迭代传递的每个项目的方式:$(this)[0].HasChildren
不必要地复杂,因为它先后将this
封装在jQuery对象中然后将其提取!
您应该只使用this.HasChildren
.
Another point is the way you address each item passed by the above iteration: $(this)[0].HasChildren
is unnecessarily complicated, because its successively encapsulates this
in a jQuery object then extracts it!
You should merely use this.HasChildren
.
建议完成整个工作的简单方法.
将HTML构建为字符串的线性流不是一个容易的方法,因为:
Building HTML as a linear flux of strings is not an easy way, because:
-
<optgroup>
的结束标记必须在创建内部<option>
之后_出现 - 但是Ajax的异步模式使得很难知道何时执行该操作
- the closing tag for
<optgroup>
must appear _after inner<option>
s have been created - but the async mode of Ajax makes difficult to know when to do it
相反,很容易使用jQuery在需要时依次构建<option>
s和<optgroup>
s.
请注意,这意味着我们必须使用jQuery.append()
而不是jQuery.html()
来做到这一点.
At the opposite it's easy to use jQuery to build <option>
s and <optgroup>
s each in turn when needed.
Note that it means we must use jQuery.append()
instead of jQuery.html()
to do that.
关于源数据的嵌套方面,最简单的方法是在嵌套级别中使用递归而不是多次使用$.ajax
.
它还具有减少代码并使其更具可读性的优点.
Regarding the nested aspect of the source data, the simplest way is to use recursion rather than using $.ajax
several times in nested levels.
It also has the advantage of reducing the code and making it more readable.
以下是基于上述所有考虑因素的摘要.
请注意,在我之前的建议之后,我还简化了它,仅使用HasChildren
(为清晰起见,更名为Children
)来提供有关嵌套的<optgroup>
的信息.对于<option>
,它甚至不必存在.
Here is the snippet founded on all the above considerations.
Note that I also simplified it following my previous suggestion to merely use HasChildren
(renamed Children
for clarity) to provide the information about nested <optgroup>
. For an <option>
it not even has to be present.
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~');
可以肯定的是,我测试了一个稍微修改的版本,您可以尝试检查它是否按预期工作:
To be sure, I tested with a slightly modified version you can try to check it works as expected:
<?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>
这篇关于级联AJAX响应以访问具有"hasChildren"的对象.不包含在JSON对象中的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!