级联父子项从动态JSON数据中选择框

时间:2016-08-08 08:12:36

标签: javascript angularjs

我已经从JSON数据动态创建了一些链式选择框,我将从服务器收到这些数据。链接/级联的工作方式是每个选择框都是具有以下属性的命名对象:

  1. 父属性:作为此选择框对象的父对象的对象名称。
  2. 选项:选项对象的数组,其中每个对象包含:(a)选项值(b)父选项值 - 用于映射当前值的父选择框值。 (c)选项ID。

  3. 选定选项:具有两个属性的对象:(a)当前选定的值(b)当前所选值的ID。

  4. 我在“选项”标签中使用ng-repeat创建选择框,或者在“select”标签中使用ng-option创建选择框,然后我使用自定义过滤器,我通过匹配来过滤检索到的选项(2)具有其父对象的“当前选择值”(3> a)的选项值(2> a)的父选项值(2> b)。基本上使用自定义过滤器从子选项值到选定的父值进行多对一映射。

    enter image description here

    我能够正确映射父子选择框,但问题是当我更改父选择框值时,其子对象的“选定选项值”不会更新(子选定项目不会获取已过滤列表中的第一项,导致孙子下拉列表无法更新。 [1]

    如果父值发生变化,是否有任何方法,使用第一个选项值而不是当前空白值初始化子选择框(以及后续的子/孙子)?

    Here is the working plunker.(ng-repeat实施)。非常感谢任何帮助。

    以下是带有ng-options实现的another plunker

    HTML(ng-repeat):

    <div ng-repeat="selection in vm.selectionData">
        <div ng-repeat="(key, attribute) in selection.attributes">
          <span>{{key}}</span>
          <select class="form-control" ng-model="attribute.selectedOption.name">
            <option ng-repeat="option in attribute.options | optionFilter : selection.attributes[attribute.parentAttr]">{{option.name}}</option>
          </select>
        </div>
    </div>
    

    HTML(ng-options):

    <div ng-repeat="selection in vm.selectionData">
        <div ng-repeat="(key, attribute) in selection.attributes">
          <span>{{key}}</span>
          <select ng-model="attribute.selectedOption" ng-options="attribute.name for attribute in (attribute.options | optionFilter : selection.attributes[attribute.parentAttr]) track by attribute.id">
          </select>
        </div>        
    </div>
    

    JS:

    myApp.filter('optionFilter', function() {
      return function(items, parent) {
        var result = [];
        if (parent) {
          for (var i = 0; i < items.length; i++) {
            console.log(items[0].parent, parent.selectedOption.name);
            if (items[i].parent === parent.selectedOption.name) {
              result.push(items[i]);
            }
          }
          return result;
        } else {
          return items;
        }
      }
    });
    
    myApp.controller("MyCtrl", function($scope) {
    
      this.selectionData = [{
        selectionType: "Geography",
        attributes: {
          country: {
            parentAttr: "none",
            options: [{
              name: "India",
              parent: "None",
              id: 1
            }, {
              name: "Bangladesh",
              parent: "None",
              id: 2
            }, {
              name: "Afganistan",
              parent: "None",
              id: 3
            }],
            selectedOption: {
              name: "India",
              id: 1
            }
          },
          state: {
            parentAttr: "country",
            options: [{
              name: "Rajasthan",
              parent: "India",
              id: 1
            }, {
              name: "Haryana",
              parent: "India",
              id: 2
            }, {
              name: "Dhaka",
              parent: "Bangladesh",
              id: 3
            }, {
              name: "Kabul",
              parent: "Afganistan",
              id: 4
            }],
            selectedOption: {
              name: "Rajasthan",
              id: 1
            }
          },
          city: {
            parentAttr: "state",
            options: [{
              name: "Kota",
              parent: "Rajasthan",
              id: 1
            }, {
              name: "Sirsa",
              parent: "Haryana",
              id: 2
            }, {
              name: "Alwar",
              parent: "Rajasthan",
              id: 3
            }, {
              name: "Gurgaon",
              parent: "Haryana",
              id: 4
            }, {
              name: "Kabul",
              parent: "Kabul",
              id: 5
            },{
              name: "Dhaka",
              parent: "Dhaka",
              id: 6
            }
            ],
            selectedOption: {
              name: "Kota",
              id: 1
            }
          }
        },
      }];
    
    });
    

    参考文献:

1 个答案:

答案 0 :(得分:2)

经过一段时间的努力,我想出了一个解决方案(虽然不确定它是否符合最佳实践)。在我的自定义过滤器中,它根据父对象的选定选项值返回已过滤的选项,我另外发送当前的选择框对象。然后,

  1. 过滤器首先检查父对象是否存在,否则返回所有选项。
  2. 如果父项存在,则循环遍历当前选择框对象的所有可用选项。
  3. 如果当前选择框选项的父值与父对象的选定选项值匹配,则仅当父对象的选定选项不为空时,它才会在结果数组中推送已过滤的选项值 (当祖父项值更改且父级未获取结果筛选选项时,父对象的选定选项可以为空,从而导致父选择框中的第一个空白选项)。这将暂时导致当前选择框完全为空,因为父对象的选定选项为空。
  4. 然后,它会检查当前选择框对象的所选选项是否为空。如果是这样,它将结果数组的第一个元素(对象)分配给选定的选项对象,并返回结果数组。由于过滤器将针对所有选择框(祖父,父和子)运行,因此它会将父过滤数组中的第一个元素设置为父对象的选定选项。现在,当父对象的selected选项不再为null时,当前选择框将显示已筛选的选项(来自结果数组),结果数组的第一个元素将分配给当前选择框的选定选项。
  5. Working demo here.请分享是否有更好的解决方案。 以下是自定义过滤器:

    myApp.filter('optionFilter', function() {
      return function(items, parent, self) {
        var result = [];
        if (parent) {
          for (var i = 0; i < items.length; i++) {
            if (parent.selectedOption !== null && items[i].parentValue === parent.selectedOption.value) {
              result.push(items[i]);
            }
          }
          if (self.selectedOption === null) {
            self.selectedOption = result[0];
          }
          return result;
        } else {
          return items;
        }
      }
    });
    

    <强> HTML:

    <div ng-repeat="(key, item) in data">
        <span>{{key}}</span>
        <select ng-model="item.selectedOption" ng-options="option.value for option in (item.availableOptions | optionFilter : data[item.parent] : item) track by option.id">
        </select>
    </div>
    

    数据:

    this.data = {
      Country: {
        parent: "None",
        availableOptions: [{
          value: "United States",
          parentValue: "None",
          id: 1
        }, {
          value: "China",
          parentValue: "None",
          id: 2
        }, {
          value: "India",
          parentValue: "None",
          id: 3
        }],
        selectedOption: {
          value: "United States",
          parentValue: "None",
          id: 1
        }
      },
      State: {
        parent: "Country",
        availableOptions: [{
          value: "California",
          parentValue: "United States",
          id: 1
        }, {
          value: "Shanghai",
          parentValue: "China",
          id: 2
        }, {
          value: "Delhi",
          parentValue: "India",
          id: 3
        }],
        selectedOption: {
          value: "California",
          parentValue: "United States",
          id: 1
        }
      },
      City: {
        parent: "State",
        availableOptions: [{
          value: "Greenfield",
          parentValue: "California",
          id: 1
        }, {
          value: "Shanghai",
          parentValue: "Shanghai",
          id: 2
        }, {
          value: "New Delhi",
          parentValue: "Delhi",
          id: 3
        }],
        selectedOption: {
          value: "Greenfield",
          parentValue: "California",
          id: 1
        }
      }
    };