级联AJAX响应以访问具有"hasChildren"的对象.不包含在JSON对象中的对象 [英] Cascading AJAX response to access objects that "hasChildren" that are not included in the JSON object

查看:71
本文介绍了级联AJAX响应以访问具有"hasChildren"的对象.不包含在JSON对象中的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆