Knockout JS中的多个依赖选择

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Knockout JS中的多个依赖选择相关的知识,希望对你有一定的参考价值。

我正在尝试在Knockout JS中使用一系列依赖选择。我可以让一个人在this线程之后工作,但我很难获得多个操作。

想法是拥有主题和级别,并允许用户一次选择一个主题和一个(或多个)级别。

例如:

用户在主选择中选择“数学”。依赖选择然后将选项更改为“微积分,代数,几何”。用户选择三个中的两个。

到目前为止很简单。

然后,用户想要选择另外一对主题和级别。因此,单击一个按钮,添加另一行主要和从属选择元素。用户选择“英语”和从属选择更改选项为“语言,文学,历史”,以便他们也可以从中选择。

现在有两行选择。一个是主题数学,另一个是学科英语。

我试图让这个工作在jsfiddle,但由于原因我不完全确定这个东西甚至不会加载。

self.subjLevList = ko.observableArray([
    {subject: "Math", levels: ["Calculus", "Algebra"]},
    {subject: "English", levels: ["Language", "Literature"]} ]);

我一直盯着这个这么久我可能错过了一些明显的东西,但如果有人可以帮助我,那将非常感激:)

答案

修复参考错误

由于原因,我不完全确定这个东西甚至不会加载

您的浏览器的开发者工具是您的朋友。如果您的视图无法呈现,则敲除通常会在控制台中提供方便的错误消息。在你的情况下,第一个是这样的:

未捕获的ReferenceError:无法处理绑定foreach: function (){return subjLevVM.subjLevList }消息:subjLevVM未定义

这意味着你的绑定上下文中有一些错误:没有名为subjLevVM的属性,因此无法访问数组subjLevList

这是一个fiddle,修复了所有参考错误。如果你发现很难找到这些,请看看this answer I wrote earlier

实现描述的行为

您的目标行为并不容易创建。我开始在你当前的小提琴实现,但不得不改变太多,以至于没有更清楚......

最终,我在一系列RowsLabsoptions中重新实现了这个结构。

  • 如果仍然没有使用Labs,则只能添加行
  • 更改Row的实验室时,您只能从未使用的实验室中选择

每个图层都使用computed属性来限制选项。如果代码的任何部分不清楚或难以理解,请告诉我,我将很乐意进一步澄清。

var Lab = function(name, id, options, labsInUse) {
  this.name = name;
  this.id = id;
  
  this.options = options;
  this.selectedOptions = ko.observableArray([]);
  
  this.disabled = ko.pureComputed(function() {
    return labsInUse().some(function(thatId) {
      return thatId === id;
    });
  });
};

Lab.fromData = function(d, idsInUse) {
  return new Lab(d.lab_name, d.id, d.lab_options.split(","), idsInUse);
}

var Row = function(labs) {
  this.labs = labs;
  
  this.selectedLab = ko.observable(labs.find(function(l) {
      return !l.disabled();
    })
  );
  
  this.setOptionDisable = function(option, item) {
    ko.applyBindingsToNode(option, { disable: item.disabled }, item);
  }
};

var App = function(courseData, initialSelection) {

  this.rows = ko.observableArray([]);

  // Every lab can only be added once
  var labIdsInUse = ko.pureComputed(function() {
    return this.rows().map(function(r) {
      return r.selectedLab() && r.selectedLab().id;
    });
  }, this);
  
  var labs = courseData.map(function(d) {
    return Lab.fromData(d, labIdsInUse)
  });
  
  // Display a report of selections
  this.selection = ko.pureComputed(function() {
    return this.rows()
      .map(function(r) {
        var lab = r.selectedLab();
        return lab.name + ", with subjects: " + lab.selectedOptions().join(", ");
      });
  }, this);
  
  this.canAdd = ko.pureComputed(function() {
    return labs.length > labIdsInUse().length;
  }, this);
  
  this.addRow = function() {
    this.rows.push(new Row(labs));
  }.bind(this);
  
  this.removeRow = function(row) {
    this.rows.remove(row);
  }.bind(this);
  
  // Set initial selection
  Object.keys(initialSelection)
    .map(function(labName) {
      var row = new Row(labs);
      var labToSelect = labs.find(function(lab) {
        return lab.name === labName;
      });
      
      // Set options
      labToSelect.selectedOptions(
        initialSelection[labName]
      );
      
      // Add lab to row
      row.selectedLab(labToSelect);
      
      // Add row to app
      this.rows.push(row);
      
    }.bind(this));
};

ko.applyBindings(
  new App(
    getCourseData(),
    {"Math": ["Calculus", "Algebra"], "English": ["Language"]}  
  )
);


function getCourseData(){return[{id:"1003",lab_name:"Math",lab_index:"1",lab_options:"Calculus,Algebra,Geometry"},{id:"1004",lab_name:"English",lab_index:"2",lab_options:"Language,Literature,History"},{id:"1005",lab_name:"History",lab_index:"3",lab_options:"Ancient,Modern"}]}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="foreach: rows">
  <div>
    <select data-bind="options: labs, optionsText: 'name', value: selectedLab, optionsAfterRender: setOptionDisable"></select>
    <!-- ko with: selectedLab -->
    <select data-bind="options: options, selectedOptions: selectedOptions" multiple></select> 
    <!-- /ko -->
    <button data-bind="click: $parent.removeRow">delete</button>
  </div>
</div>

<button data-bind="click: addRow, enable: canAdd">add lab</button>

<h3>Selection:</h3>
<ul data-bind="foreach: selection">
  <li data-bind="text: $data"></li>
</ul>

以上是关于Knockout JS中的多个依赖选择的主要内容,如果未能解决你的问题,请参考以下文章

Knockout.js 与多个 Select2 绑定

将多个输入绑定到可观察数组中的同一变量(Knockout.JS)

knockout.js 中的多个过滤器

使用 Knockout 订阅的循环依赖

Chrome-Devtools代码片段中的多个JS库

将选择列表添加到可编辑网格 Knockout.js