(淘汰赛)使组合框选择的属性更改绑定组合框的选项列表

(knockout) make the a combobox selection's attribute change a Bonded combobox's option list

我编写了一个剔除模板示例,允许从组合框(列表一)中进行选择,这将导致有界组合框(列表二)的选项列表发生变化。应该发生的变化是新加载的选项列表应该只包含与第一个组合框(列表一)中选择的选项具有相同 "fieldtype" 属性值的选项。

当页面第一次加载时,第二个组合框(列表二)的第一次加载看起来不错,但是当第一个组合框选择更改时,第二个选项列表没有正确更改。

这是一个 fiddle,里面有我的代码:my code in fiddle

任何人都可以指导我如何进行这项工作吗?

    <link rel="stylesheet" href="css/queryBuilder/Bootstrap/css/bootstrap.min.css" />
<link rel="stylesheet" href="css/queryBuilder/styles.css" />
<script src="../libs/knockout.js"></script>


<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~MODEL~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<div class="container">
  <div data-bind="with: group">
    <div data-bind="template: templateName"></div>
  </div>
</div>

<!-- ~~~~~~~~~~~~~~~group-template~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<script type="text/html" id="group-template">
<br>
The intent of this page is that when <b>List One</b> selection changes <b>List Two</b> options reload with just the options from the get_jsonAttrList() call that have the same "fieldtype" as <b>List One</b>'s selection.
<br>
<br>
  <div class="alert alert-warning alert-group" style="border-width: 5px;border-color:blue;">
    List One: 
    <select data-bind="options: attributesAvailable, 
                     optionsText: 'display', 'fieldtype', 
                     selectedOptions: compareAttrObject, 
                     value: compareAttrObject
                    ">
    </select>
    <br>
    List Two:  
    <select data-bind="options: attributesAvailable2(), 
                     optionsText: 'display', 'fieldtype', 
                     selectedOptions: compareToAttrObject, 
                     value: compareToAttrObject
                    ">        
    </select>
  </div>
</script>


<script>
  window.addEventListener('load', function() {
    ko.applyBindings(new QueryBuilder.ViewModel());
  }, true);

function get_jsonAttrList() {
      return [{
          "dbcolumn" : "fid",
          "display" : "id #",
          "fieldtype" : "Number"
        }, {
          "dbcolumn": "fname",
          "display": "first name",
          "fieldtype": "Text"
        }, {
          "dbcolumn": "Apply_d",
          "display": "Application date",
          "fieldtype": "Date"
        }, {
          "dbcolumn": "location",
          "display": "location",
          "fieldtype": "Text"
        }, {
          "dbcolumn": "press_in",
          "display": "press in",
          "fieldtype": "Text"
        }, {
          "dbcolumn": "node1",
          "display": "node count",
          "fieldtype": "Number"
        }, {
          "dbcolumn": "comments",
          "display": "comments",
          "fieldtype": "Text"
        }, {
          "dbcolumn": "reg1_posname",
          "display": "Position Name",
          "fieldtype": "Text"
        }, {
          "dbcolumn": "reg1_inst_",
          "display": "inst count",
          "fieldtype": "Number"
        }, {
          "dbcolumn": "create_d8",
          "display": "create #",
          "fieldtype": "Number"
        }, {
          "dbcolumn": "mapped_d8",
          "display": "mapped #",
          "fieldtype": "Number"
        }, {
          "dbcolumn": "term_d",
          "display": "terminated date",
          "fieldtype": "Date"
        }, {
          "dbcolumn": "start",
          "display": "emp start date",
          "fieldtype": "Date"
        }]
    }


    //~~~~~~~~~~~~~~~~~~~~~~group~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    window.QueryBuilder = (function(exports, ko) {
      var Condition = exports.Condition;
      /**
       * creates an instants of the group template.
       */
      function Group() {
        var self = this;
        self.templateName = 'group-template';


        self.compareAttrObject = ko.observable("");
        self.attributesAvailable = ko.observable(get_jsonAttrList());
        self.compareToAttrObject = ko.observable("");
        self.attributesAvailable2 = ko.observable(new Array());

        self.compareAttrObject.subscribe(function() {
          var tempAttrList = get_jsonAttrList();
          if (tempAttrList != null && tempAttrList.length > 0) {
            if (self.compareAttrObject() != undefined && self.compareAttrObject()[0] != null) {
              alert("Length of list two BEFORE list one changed to ["+
                        self.compareAttrObject()[0].fieldtype+
                        "]..." + self.attributesAvailable2().length);

    //fail after firt//                
        self.attributesAvailable2 = ko.observable(new Array());
    //fail after firt//self.attributesAvailable2(new Array());
    //fail all//self.attributesAvailable2.splice(0,self.attributesAvailable2.length);
    //fail after first//while(self.attributesAvailable2.length > 0) {self.attributesAvailable2.pop();}

              for (var i = 0; i < tempAttrList.length; i++) {
                if (tempAttrList[i].fieldtype == self.compareAttrObject()[0].fieldtype) {
                  self.attributesAvailable2().push(tempAttrList[i]);
                }
              }
              alert("Length of list two AFTER list one changed to ["+
                        self.compareAttrObject()[0].fieldtype+
                        "]..." + self.attributesAvailable2().length);
            }
          }
        });


      }
      exports.Group = Group;
      return exports;
    })(window.QueryBuilder || {}, window.ko);

    //~~~~~~~~~~view model~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    window.QueryBuilder = (function(exports, ko) {

      var Group = exports.Group;

      function ViewModel() {
        var self = this;
        self.group = ko.observable(new Group());
      }

      exports.ViewModel = ViewModel;
      return exports;

    })(window.QueryBuilder || {}, window.ko);

</script>

您的代码似乎对处理对象还是数组感到困惑。 fiddle 中的 bootstrap 下拉列表似乎不允许多 select,因此一次只能有一个 selected 项目。

您可以从模板中的 select 中删除 "selectedOptions" 绑定,并将 compareAttrObject(s) 保留为可观察对象。然后,您可以使用 compareAttrObject()[0].

之类的索引器摆脱所有访问对象的地方

您的选项列表 应该 是数组,因此它们应该声明为 ko.observableArray() 而不是 ko.observable()

最后,您需要确保更新您的可观察对象,而不是替换它们并破坏绑定。每次您的订阅触发时,它都会用一个新的可观察数组替换 attributesAvailable2。这应该是通过删除现有项目并仅添加过滤后的项目来修改现有的可观察数组。

function get_jsonAttrList() {
  return [{ "dbcolumn" : "fid", "display" : "id #", "fieldtype" : "Number" }, { "dbcolumn": "fname", "display": "first name", "fieldtype": "Text" }, { "dbcolumn": "Apply_d", "display": "Application date", "fieldtype": "Date" }, { "dbcolumn": "location", "display": "location", "fieldtype": "Text" }, { "dbcolumn": "press_in", "display": "press in", "fieldtype": "Text" }, { "dbcolumn": "node1", "display": "node count", "fieldtype": "Number" }, { "dbcolumn": "comments", "display": "comments", "fieldtype": "Text" }, { "dbcolumn": "reg1_posname", "display": "Position Name", "fieldtype": "Text" }, { "dbcolumn": "reg1_inst_", "display": "inst count", "fieldtype": "Number" }, { "dbcolumn": "create_d8", "display": "create #", "fieldtype": "Number" }, { "dbcolumn": "mapped_d8", "display": "mapped #", "fieldtype": "Number" }, { "dbcolumn": "term_d", "display": "terminated date", "fieldtype": "Date" }, { "dbcolumn": "start", "display": "emp start date", "fieldtype": "Date" }] 
}


//~~~~~~~~~~~~~~~~~~~~~~group~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
window.QueryBuilder = (function(exports, ko) {
  var Condition = exports.Condition;
  /**
   * creates an instants of the group template.
   */
  function Group() {
    var self = this;
    self.templateName = 'group-template';


    self.compareAttrObject = ko.observable();
    self.attributesAvailable = ko.observableArray(get_jsonAttrList());
    self.compareToAttrObject = ko.observable("");
    self.attributesAvailable2 = ko.observableArray(new Array());

    self.compareAttrObject.subscribe(function() {
      var tempAttrList = get_jsonAttrList();
      if (tempAttrList != null && tempAttrList.length > 0) {
        if (self.compareAttrObject() != undefined && self.compareAttrObject() != null) {
          alert("Length of list two BEFORE list one changed to ["+
             self.compareAttrObject().fieldtype+
             "]..." + self.attributesAvailable2().length);
          
       self.attributesAvailable2.removeAll();
          for (var i = 0; i < tempAttrList.length; i++) {
            if (tempAttrList[i].fieldtype == self.compareAttrObject().fieldtype) {
              self.attributesAvailable2.push(tempAttrList[i]);
            }
          }
          alert("Length of list two AFTER list one changed to ["+
             self.compareAttrObject().fieldtype+
             "]..." + self.attributesAvailable2().length);
        }
      }
    });


  }
  exports.Group = Group;
  return exports;
})(window.QueryBuilder || {}, window.ko);

//~~~~~~~~~~view model~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
window.QueryBuilder = (function(exports, ko) {

  var Group = exports.Group;

  function ViewModel() {
    var self = this;
    self.group = ko.observable(new Group());
  }

  exports.ViewModel = ViewModel;
  return exports;

})(window.QueryBuilder || {}, window.ko);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-debug.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-ui-bootstrap/0.5pre/assets/css/bootstrap.min.css" rel="stylesheet"/>

<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~MODEL~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<div class="container">
  <div data-bind="with: group">
    <div data-bind="template: templateName"></div>
  </div>
</div>

<!-- ~~~~~~~~~~~~~~~group-template~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<script type="text/html" id="group-template">
<br>
The intent of this page is that when <b>List One</b> selection changes <b>List Two</b> options reload with just the options from the get_jsonAttrList() call that have the same "fieldtype" as <b>List One</b>'s selection.
<br>
<br>
  <div class="alert alert-warning alert-group" style="border-width: 5px;border-color:blue;">
    List One: 
    <select data-bind="options: attributesAvailable, 
                     optionsText: 'display', 'fieldtype', 
                     value: compareAttrObject
                    ">
    </select>
    <br>
    List Two:  
    <select data-bind="options: attributesAvailable2(), 
                     optionsText: 'display', 'fieldtype', 
                     value: compareToAttrObject
                    ">        
    </select>
  </div>
</script>


<script>
  window.addEventListener('load', function() {
    ko.applyBindings(new QueryBuilder.ViewModel());
  }, true);

</script>