表格上的下拉菜单,每行只能选择一个项目

时间:2018-08-29 11:49:22

标签: knockout.js

我是Knockout的新手,我已经成功地从数据源创建了一个记录表。我需要在表的每一行中添加一个带有两个选项“ Primary”和“ Secondary”的下拉列表。我需要从表中的其他项目中删除所选的选项。例如,如果表中的第一行选择了“主要”,则无需允许其他行再次选择它。我的行数未知。

1 个答案:

答案 0 :(得分:1)

要实现此功能,您的各个行需要访问其他行以检查正在使用的值。在实现此功能之前,让我们先编写一个朴素的示例,以便我们知道我们正在使用什么。

起点

如果您运行以下代码段,则会看到常规UI 没有描述的功能。

在问有关Stackoverflow的问题时,您通常会自己提供这些示例,因此人们有一个很好的起点来帮助您解决问题!但是,由于您是新的参与者,因此此人就在我身上。

function Row(id) {
  this.name = id;
  this.selectedSource = ko.observable(null);
  this.sourceOptions = [ "Primary", "Secondary" ]
};


function App() {
  this.rows = ko.observableArray([]);
  
  let lastRowId = 0;
  this.addRow = () => {
    this.rows.push(
      new Row(lastRowId++)
    );
  }
};

const app = new App();
ko.applyBindings(app);

app.addRow();
app.addRow();
app.addRow();
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<table data-bind="foreach: rows">
  <tr>
    <td data-bind="text: name"></td>
    <td>
      <select data-bind="value: selectedSource,
                         options: sourceOptions,
                         enable: sourceOptions.length,
                         optionsCaption: 'select source'">
                         </select>
    </td>
  </tr>
</table>
<button data-bind="click: addRow">add row</button>

添加新功能

以上示例假定sourceOptions的静态列表。但是实际上,它是一个计算列表:

  • 所有可能的值开头
  • 删除所有由 other 行选择的值

要实现此功能,我们首先需要访问其他行:

/* Row accepts a reference to its siblings (including itself) */
function Row(is, allRows) { /* ... */}

/* App passes a reference to all rows when constructing new ones */
new Row(0, this.rows);

现在我们可以访问其他行了,我们可以检查它们的选择并将其从可用选项列表中删除:

// Remove this row from the list
const otherRows = ko.pureComputed(() =>  
  allRows().filter(row => row !== this)
);

// Create a Set of all selections
const otherSelections = ko.pureComputed(() =>
  new Set(otherRows().map(row => row.selectedSource()))
);

// Take the Base list and remove any element that is in otherSelections
this.sourceOptions = ko.pureComputed(() =>
  [ "Primary", "Secondary" ]
    .filter(s => !otherSelections().has(s))    
);

查看下面的可运行代码段,以查看其运行情况。我还添加了一个enable绑定以指示何时没有可供选择的选项!

如果事情仍然不清楚,请发表评论。我很乐意提供帮助。

function Row(id, allRows) {
  this.name = id;
  this.selectedSource = ko.observable(null);
  
  const otherRows = ko.pureComputed(() => 
    allRows().filter(row => row !== this)
  );
  
  const otherSelections = ko.pureComputed(() =>
    new Set(otherRows().map(row => row.selectedSource()))
  );
  
  this.sourceOptions = ko.pureComputed(() =>
    [ "Primary", "Secondary" ]
      .filter(s => !otherSelections().has(s))    
  );
};


function App() {
  this.rows = ko.observableArray([]);
  
  let lastRowId = 0;
  this.addRow = () => {
    this.rows.push(
      new Row(lastRowId++, this.rows)
    );
  }
};

const app = new App();
ko.applyBindings(app);

app.addRow();
app.addRow();
app.addRow();
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<table data-bind="foreach: rows">
  <tr>
    <td data-bind="text: name"></td>
    <td>
      <select data-bind="value: selectedSource,
                         options: sourceOptions,
                         enable: sourceOptions().length,
                         optionsCaption: 'select source'">
                         </select>
    </td>
  </tr>
</table>
<button data-bind="click: addRow">add row</button>