【发布时间】:2012-10-16 12:14:50
【问题描述】:
考虑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 或其他一些非虚假值)。 - 因为
select元素中只有1个option(由于optionsCaption),并且因为valueObservable绑定到它(通过value绑定),这导致@987654332 @ 改为undefined。 - 最后,
optionsObservableArray完成并将新的option元素添加到select,但此时为时已晚:valueObservable现在包装了undefined值而不是实际数据值从第一个 ajax 调用返回。
问题:解决此问题的最佳方法是什么?这是我能想到的:
- 使用
async: false运行第一个ajax 调用。这可能会减慢页面呈现速度。 - 创建一个单独的 observable 用于绑定到选择值(例如
value: selectedValueObservable)。然后订阅optionsObservableArray并使用订阅执行self.selectedValueObservable(self.valueObservable())之类的操作。这似乎是一种创可贴。 - 通过从服务器发送选项数据(使用 MVC 视图模型),在执行任何 javascript 之前将选择和选项呈现到页面。这使得处理
observableArray的选项变得更加困难。
更新
为了简化示例代码,我从这个问题中省略了另一个问题。实际上,此视图模型用于创建可编辑的数据项列表。所以实际上有超过 1 个下拉列表被渲染到页面。 data ajax 调用确实返回了一个数组,它的成功函数确实设置了一个复杂项目的observableArray。由于下拉列表选项在每个内联表单中都重复使用,因此它被放置在 $parent 视图模型上并且只加载一次。在单个 ajax 调用中传递选择选项也很困难,因为数据项是通过 WebAPI 检索的(返回 IEnumerable,没有空间发送额外的下拉选项)。
【问题讨论】:
-
将ajax调用包装到
computed的原因是什么? -
@vittore,将 ajax 调用包装在
ko.computed中会立即执行。基本上,它通过在构造视图模型时发送 ajax 调用来初始化视图模型。 -
还有很多其他方法可以立即执行函数,而
computed似乎不是为此而设计的。
标签: asp.net-mvc asp.net-mvc-3 knockout.js asp.net-mvc-4 knockout-2.0