我有多个下拉列表,需要执行以下操作:
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及其siblingsfilterValue创建对任何更改的预订:

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/

10-07 14:38