knockout.js - 表格上的下拉菜单,允许每行仅选择一次项目
问题描述
我是 Knockout 的新手,我已经成功地从我的数据源创建了一个记录表。我需要在表中的每一行添加一个包含两个选项“主要”和“次要”的下拉列表。我需要从表中的其他项目中删除选定的选项。例如,如果表中的第一行选择了“主要”,我需要不允许再次为其他行选择它。我的行数未知。
解决方案
要实现此功能,您的各个行需要有权访问其他行以检查正在使用的值。在我们实现这个特性之前,让我们先编写一个简单的例子,这样我们就知道我们正在使用什么。
初始点
如果您运行下面的代码片段,您将看到没有您描述的功能的一般 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
。然而,实际上,它是一个计算列表:
- 从所有可能的值开始
- 删除其他行选择的所有值
要实现此功能,我们首先需要访问其他行:
/* 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>
推荐阅读
- list - 未处理的异常:键入“列表”
' 不是类型 'List 的子类型 ':颤动 - swift - 检查NSStepper是否按下了向上或向下按钮的方法?
- javascript - 创建表 sql 命令 node.js 失败
- sql - 查看一列长字符串是否包含较短字符串列表中的任何项目
- grafana - AWS Timestream 错误中的聚合计数导致错误
- amazon-s3 - python:从 s3 存储桶对象创建 Json 格式的目录结构
- javascript - 状态未更新
- amazon-web-services - 向特定 Cognito 用户组授予对 S3 存储桶的读/写访问权限
- reactjs - 无效的挂钩调用。尝试使用 useHistory 时,只能在函数组件的主体内部调用 Hooks
- amazon-web-services - 将 S3 存储桶中的所有 txt 文件合并为 1 个大文件