我有一个多下拉列表,需要执行以下操作:
1.确保在一个下拉列表中选择值时,它不会出现在其他下拉列表中(在此处找不到合适的解决方案)
2.当选择值"Text"时,将显示一个文本字段(<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());
我将在此请求您的协助!主要针对第一个问题。
谢谢
Mike
如果您想根据UI中已经选择的选项来限制选项,您需要确保每个cartLine
都有自己的过滤器阵列。让我们在构造函数中这样传递:
var CartLine = function(availableFilters) {
var self = this;
self.availableFilters = availableFilters;
// Other code
// ...
};
您必须使用这个新的视图模型属性,而不是全局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
(其他购物车行)的引用,并通过使用siblings
和其filterValue
:的ko.computed
创建对任何更改的订阅
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))
。使用空数组初始化,然后使用addFilter
推送第一个CartLine
。
关于第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>
更新了包含以下代码的fiddle:http://jsfiddle.net/z22m1798/