级联AJAX响应访问对象" hasChildren"那些未包含在JSON对象中的

时间:2016-03-16 20:40:13

标签: javascript jquery json ajax

我正在尝试构建一个下拉列表,其中包含我需要访问的子级和孙级别对象,这些对象未包含在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;
&#13;
&#13;

以下是我正在使用的数据结果示例:

...{Id: "~some guid~", Text: "Medium", Name: "Medium", HasChildren: true,…}...

因此,如果HasChildren为真,我需要根据父级的GUID级联对API的新调用。由于AJAX的异步性,我认为,UI只是构建没有孩子的最高级别选项。为了表现,我不想关闭异步,但我不知道如何在正确的时间以正确的顺序获得我的回复。

我想我可能需要构建一个回调函数来处理排序,然后在结束时执行更新触发器,但我没有太多经验,我不确定这是正确的方向。

感谢您的帮助!

1 个答案:

答案 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>后出现
  • 但Ajax的异步模式很难知道何时这样做

相反,在需要时,可以轻松使用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>