select
考虑元素上的以下 ko 绑定:
<select data-bind="value: valueObservable, options: optionsObservableArray,
optionsCaption: '[None] - this is an optional field'">
...给定如下视图模型:
function MyViewModel()
{
var self = this;
self.valueObservable = ko.observable();
self.optionsObservableArray = ko.observableArray();
// ajax call to load options
ko.computed(function() {
$.ajax(...)
.success(function(optionsResponse) {
self.optionsObservableArray(optionsResponse)
});
});
// ajax call to load data value
ko.computed(function() {
$.ajax(...)
.success(function(valueResponse) {
self.valueObservable(valueResponse)
});
});
}
奇怪的是,第二个(数据)ajax 调用在第一个(选项)ajax 调用之前返回。由于select
元素具有optionsCaption
绑定,这就是我认为正在发生的事情:
- 数据 ajax 调用完成,将 设置
valueObservable
为某个值(如 6、abc 或其他一些非假值)。 - 因为元素中只有 1
option
(select
由于optionsCaption
),并且因为valueObservable
绑定到它(通过value
绑定),所以这会导致valueObservable
被更改为undefined
。 - 最后,
optionsObservableArray
完成并向 中添加新option
元素select
,但此时为时已晚:valueObservable
现在包装的是一个undefined
值,而不是第一次 ajax 调用返回的真实数据值。
问题:解决此问题的最佳方法是什么?这是我能想到的:
- 使第一个 ajax 调用使用
async: false
. 这可能会减慢页面呈现速度。 - 创建一个单独的 observable 以绑定到选择值(例如
value: selectedValueObservable
)。然后订阅optionsObservableArray
并使用订阅执行类似的操作self.selectedValueObservable(self.valueObservable())
。这似乎是一个创可贴修复。 - 通过从服务器发送选项数据(使用 MVC 视图模型),在执行任何 javascript 之前将选择和选项呈现到页面。这使得将选项作为
observableArray
.
更新
为了简化示例代码,我从这个问题中省略了另一个问题。实际上,此视图模型用于创建可编辑的数据项列表。所以实际上有超过 1 个下拉列表被渲染到页面。data ajax 调用确实返回了一个数组,它的成功函数确实设置了一个observableArray
复杂的项。由于下拉列表选项在每个内联表单中都重复使用,因此它被放置在$parent
视图模型上并且只加载一次。在单个 ajax 调用中传递选择选项也很困难,因为数据项是通过 WebAPI 检索的(它返回一个IEnumerable
,没有空间发送额外的下拉选项)。