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

Javascript 从动态JSON数据级联父子选择框,javascript,angularjs,Javascript,Angularjs,我已经从服务器接收的JSON数据中动态创建了一些链式选择框。链接/级联的工作方式是,每个选择框都是具有以下属性的命名对象: 父属性:此选择框对象的父对象的名称 选项:选项对象数组,其中每个对象包含:(a)选项值(b)父选项值-映射当前值的父选择框值。(c) 选项ID 选定选项:具有两个属性的对象:(a)当前选定值(b)当前选定值的ID 我正在使用“选项”标记中的ng repeat或“选择”标记中的ng option创建选择框,然后使用自定义过滤器,通过将选项值(2>a)的父选项值(2>b)与其父

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

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

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

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

    我能够正确映射父子选择框,但问题是当我更改父选择框值时,其子对象的“选定选项值”不会更新(子选定项不会捕获筛选列表中的第一项,导致“孙子”下拉列表不更新)

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

    (重复执行)。我会非常感谢你的帮助

    下面是使用ng选项实现的示例

    HTML(ng重复):

    <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>
    
    <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>
    
    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
            }
          }
        },
      }];
    
    });
    
    <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
        }
      }
    };
    
    
    {{key}}
    {{option.name}
    
    HTML(ng选项):

    <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>
    
    <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>
    
    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
            }
          }
        },
      }];
    
    });
    
    <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
        }
      }
    };
    
    
    {{key}}
    
    JS:

    <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>
    
    <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>
    
    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
            }
          }
        },
      }];
    
    });
    
    <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
        }
      }
    };
    
    myApp.filter('optionFilter',function(){
    返回函数(项目、父项){
    var结果=[];
    如果(家长){
    对于(变量i=0;i

    参考资料:


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

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

    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;
        }
      }
    });
    

    如何在原生js中应用它,或者如何在m中应用它