我有多个下拉列表,需要执行以下操作:
1.确保在一个下拉列表中选择值时,它不会出现在其他列表中(此处找不到合适的解决方案)。
2.选择值“文本”时,将出现一个文本字段(<input>
),而不是“是/否”下拉列表。
3.“选择选项”将仅出现在第一行(仍在起作用)。
4.确保如果选择“文本”,它将始终位于顶部(仍在工作)。
JSFiddle
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());
我会在这里感谢您的协助!主要针对第一个问题。
谢谢!
麦克风
最佳答案
如果要基于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)剩下的唯一的事情就是用户体验决定而不是“编码决定”:您是否希望用户在添加新的决定后能够更改以前的“选择”?在这种情况下,您需要创建计算的
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排序的可计算观察值:
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/