1

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绑定,这就是我认为正在发生的事情:

  1. 数据 ajax 调用完成,将 设置valueObservable为某个值(如 6、abc 或其他一些非假值)。
  2. 因为元素中只有 1 optionselect由于optionsCaption),并且因为valueObservable绑定到它(通过value绑定),所以这会导致valueObservable被更改为undefined
  3. 最后,optionsObservableArray完成并向 中添加新option元素select,但此时为时已晚:valueObservable现在包装的是一个undefined值,而不是第一次 ajax 调用返回的真实数据值。

问题:解决此问题的最佳方法是什么?这是我能想到的:

  1. 使第一个 ajax 调用使用async: false. 这可能会减慢页面呈现速度。
  2. 创建一个单独的 observable 以绑定到选择值(例如value: selectedValueObservable)。然后订阅optionsObservableArray并使用订阅执行类似的操作self.selectedValueObservable(self.valueObservable())。这似乎是一个创可贴修复。
  3. 通过从服务器发送选项数据(使用 MVC 视图模型),在执行任何 javascript 之前将选择和选项呈现到页面。这使得将选项作为observableArray.

更新

为了简化示例代码,我从这个问题中省略了另一个问题。实际上,此视图模型用于创建可编辑的数据项列表。所以实际上有超过 1 个下拉列表被渲染到页面。data ajax 调用确实返回了一个数组,它的成功函数确实设置了一个observableArray复杂的项。由于下拉列表选项在每个内联表单中都重复使用,因此它被放置在$parent视图模型上并且只加载一次。在单个 ajax 调用中传递选择选项也很困难,因为数据项是通过 WebAPI 检索的(它返回一个IEnumerable,没有空间发送额外的下拉选项)。

4

2 回答 2

1

有什么理由不先进行ajax调用并在完成时应用绑定吗?

$.when(getOptions(), getData()).done(bind) 


function getOptions() { 
    return $.ajax(...).success(vm.optionsObservableArray)
}

function getData() {
    return $.ajax(...).success(vm.valueObservable)
}

function bind() {
    ko.applyBindings(vm, document.getElementById('elem')) 
} 
于 2012-10-16T13:44:16.600 回答
1

如果可能的话,我建议您进行一次 ajax 调用。使您的控制器返回具有对象数组和选定值的复杂对象:

// ajax call to load options and data value
ko.computed(function() {
    $.ajax(...)
    .success(function(response) {
        self.optionsObservableArray(response.options);
        self.valueObservable(response.value);
    });
});

如果无法合并两个 ajax 调用,您可以将第二个 ajax 调用放到第一个 ajax 的成功回调中:

// ajax call to load options
ko.computed(function() {
    $.ajax(...)
    .success(function(optionsResponse) {
        self.optionsObservableArray(optionsResponse)

        // ajax call to load data value
        $.ajax(...)
        .success(function(valueResponse) {
             self.valueObservable(valueResponse)
        });
    });
});
于 2012-10-16T12:29:11.400 回答