knockoutjs 将项目列表绑定到下拉列表

knockoutjs bind list of items to dropdown

我有这个下拉控件:

<select class="form-control" 
        data-bind="attr: { id: 'prefix_' + $index() }, 
                   options: TeacherNames(), 
                   optionsValue: 'TeacherId', 
                   optionsText: 'TeacherName', 
                   optionsCaption: 'Choose Teacher', 
                   event: { change: $root.permissionChanged }">
</select>

然后我尝试通过以下方式设置下拉列表中的值:

item.TeacherNames = ko.computed(function() {
  return getTeacherList(item.OrderId);
});

function getTeacherList(orderId) {
  $.ajax({
    type: "POST",
    url: "/webservices/WebServiceTeacher.asmx/GetTeachersForMyAccount",
    contentType: "application/json; charset=utf-8",
    data: "{'Id': " + JSON.stringify(orderId) + "}",
    dataType: "json",
    success: function(data) {
      if (data.d) {
        return data.d;
      }
    },
    error: function(n) {
      alert('Error');
    }
  });
}

我可以从 Web 服务取回教师数据,但无法实际设置 select 列表中的值。

select 控件是 foreach 绑定的一部分:

<!-- ko foreach: Orders -->
<div class="row">
  <div class="col-md-12 m-t-20">
    <hr class="blue" />
  </div>
  <div class="col-md-12">
    <div class="row order-gray-bk col-wrap">
      <div class="col-lg-9 col-md-9 n-m-t m-r-10 p-t-10 p-b-10">
        <div class="row">
          <div class="col-sm-2 col-xs-4 n-p">
            Teacher:
            <select class="form-control" 
                    data-bind="attr: { id: 'prefix_' + $index() }, 
                               options: TeacherNames(), 
                               optionsValue: 'TeacherId', 
                               optionsText: 'TeacherName', 
                               optionsCaption: 'Choose Teacher', 
                               event: { change: $root.permissionChanged }">
            </select>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
<!-- /ko -->

在每个订单的 foreach 循环中触发对 Web 服务的调用:

ko.utils.arrayForEach(data.d, function(item) {
  item.TeacherNames = ko.computed(function() {
    return getTeacherList(item.OrderId);
  });
  self.Orders.push(item);
});

你把事情搞混了。 computed 适用于根据视图模型的其他部分而变化的部分视图模型。计算 中的函数被触发 一次 Knockout 认为 computed 必须是 re-evaluated.

相反,有一个像这样的常规 observableArray:

item.TeacherNames = ko.observableArray([]);

然后在方便的时候填充该数组(页面加载,或者当用户切换到页面上的某个选项卡时,或者当 orderId 更改时,或者...):

function getTeacherList(orderId) {
  $.ajax({
    url: "/webservices/WebServiceTeacher.asmx/GetTeachersForMyAccount",
    data: "{'Id': " + JSON.stringify(orderId) + "}",
    dataType: "json",
    success: function(data) {
      item.TeacherNames(data.TeacherNames);
    }
  });
}

举个具体的例子,如果你想在orderId(假设是一个observable)发生变化时刷新教师姓名:

item.orderId.subscribe(function(newVal) {
  if (newVal !== item.orderId()) {
    getTeacherList(newVal);
  }
});

作为脚注,计算的可观察值会很好,例如用于显示已排序的列表:

item.sortedTeacherNames = ko.computed(function() {
  return item.TeacherNames().sort();
});

如果您更改相关的 TeacherNames 可观察数组,sortedTeacherNames自动更新

PS。如果 TeacherNamescomputedobservableArray 你可以只做 options: TeacherNames (没有括号),因为 KO 知道如何在数据绑定中处理这些类型。