我有一个多下拉列表,我需要执行以下操作:
1.确保在一个下拉列表中选择值时,它不会出现在其他列表中(此处无法找到正确的解决方案)。
2.选择值&#34; Text&#34;文本字段(<input>
)将显示而不是“是/否”下拉列表
3.&#34;选择选项&#34;将仅出现在第一行(仍在使用它)
4.确保如果&#34; Text&#34;如果被选中,它将始终位于顶部(仍在处理它)。
HTML :
<div class='liveExample'>
<table width='100%'>
<tbody data-bind='foreach: lines'>
<tr>
<td>
Choose option:
</td>
<td>
<select data-bind='options: filters, optionsText: "name", value: filterValue'> </select>
</td>
<td data-bind="with: filterValue">
<select data-bind='options: filterValues, optionsText: "name", value: "name"'> </select>
</td>
<td>
<button href='#' data-bind='click: $parent.removeFilter'>Remove</button>
</td>
</tr>
</tbody>
</table>
<button data-bind='click: addFilter'>Add Choice</button>
JAVASCRIPT :
var CartLine = function() {
var self = this;
self.filter = ko.observable();
self.filterValue = ko.observable();
// Whenever the filter changes, reset the value selection
self.filter.subscribe(function() {
self.filterValue(undefined);
});
};
var Cart = function() {
// Stores an array of filters
var self = this;
self.lines = ko.observableArray([new CartLine()]); // Put one line in by default
// Operations
self.addFilter = function() { self.lines.push(new CartLine()) };
self.removeFilter = function(line) { self.lines.remove(line) };
};
ko.applyBindings(new Cart());
我会在这里呼吁你的帮助!主要是第一个问题。
谢谢!
麦克
答案 0 :(得分:2)
如果您想根据UI中已选择的选项限制选项,您需要确保每个cartLine
都有自己的过滤器数组。让我们在构造函数中传递它,如下所示:
var CartLine = function(availableFilters) {
var self = this;
self.availableFilters = availableFilters;
// Other code
// ...
};
您必须使用此新的viewmodel属性而不是全局filters
数组:
<td>
<select data-bind='options: availableFilters,
optionsText: "name",
value: filterValue'> </select>
</td>
现在,在创建新的cartLine
实例时,我们必须找出哪些过滤器仍然可用。 Cart
管理所有lines
,并具有addFilter
功能。
self.addFilter = function() {
var availableFilters = filters.filter(function(filter) {
return !self.lines().some(function(cartLine) {
var currentFilterValue = cartLine.filterValue();
return currentFilterValue &&
currentFilterValue.name === filter.name;
});
});
self.lines.push(new CartLine(availableFilters))
};
新CartLine
实例仅获取尚未在任何其他行中使用的过滤器。 (注意:如果您想在旧版浏览器中使用Array.prototype.some
,则可能需要polyfill)
唯一剩下的就是用户体验决策而不是编码决策&#34;:您是否希望用户能够改变以前的选择&#34;添加新的?如果是这种情况,您需要创建计算availableFilters
数组而不是普通数组。
这是一个分叉的小提琴,其中包含我在上面发布的代码:http://jsfiddle.net/ztwcqL69/请注意,您可以创建双倍选择,因为在添加新选项后,选项仍然可以编辑。如果您评论所需的行为,我可以帮助您弄清楚如何做到这一点。这可能需要一些更激烈的改变......我提供的解决方案更多的是指向正确方向的指针。
编辑:我觉得不提供最终解决方案很糟糕,所以这是另一种方法:
如果您想要追溯更新availableFilters
,可以这样做:
CartLine
获取对其siblings
(其他购物车行)的引用,并通过使用ko.computed
的siblings
创建对所有更改的订阅他们的filterValue
:
var CartLine = function(siblings) {
var self = this;
self.availableFilters = ko.computed(function() {
return filters.filter(function(filter) {
return !siblings()
.filter(function(cartLine) { return cartLine !== self })
.some(function(cartLine) {
var currentFilterValue = cartLine.filterValue();
return currentFilterValue &&
currentFilterValue.name === filter.name;
});
});
});
// Other code...
};
像这样创建新的购物车行:self.lines.push(new CartLine(self.lines))
。使用空数组启动,然后使用CartLine
推送第一个addFilter
。
关于第2点:您可以创建一个基于filterValue进行排序的计算observable:
self.sortedLines = ko.computed(function() {
return self.lines().sort(function(lineA, lineB) {
if (lineA.filterValue() && lineA.filterValue().name === "Text") return -1;
if (lineB.filterValue() && lineB.filterValue().name === "Text") return 1;
return 0;
});
});
第3点:将其移到foreach
。
第4点:使用if
绑定:
<td data-bind="with: filterValue">
<!-- ko if: name === "Text" -->
<input type="text">
<!-- /ko -->
<!-- ko ifnot: name === "Text" -->
<select data-bind='options: filterValues, optionsText: "name", value: "name"'> </select>
<!-- /ko -->
<td>
包含此代码的更新小提琴:http://jsfiddle.net/z22m1798/