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)
        });
    });
}

これについて奇妙なのは、2 番目の (データ) ajax 呼び出しが最初の (オプション) ajax 呼び出しの前に返される場合です。select要素にはバインディングがあるため、これoptionsCaptionが起こっていると私が信じていることです:

  1. データ ajax 呼び出しが完了し、valueObservable何らかの値 (6、abc、またはその他の偽でない値など) が設定されます。
  2. option要素には 1 つしかなくselect( によりoptionsCaption)、valueObservableが (バインディングを介してvalue) バインドされているため、これにより がvalueObservableに変更されundefinedます。
  3. 最後に、は に新しい要素をoptionsObservableArray完成させて追加しますが、この時点では手遅れです。 は、最初の ajax 呼び出しから返された実際のデータ値ではなく、値をラップしています。optionselectvalueObservableundefined

質問: これを回避する最善の方法は何ですか? これが私が考えることができるものです:

  1. で最初の ajax 呼び出しを実行しasync: falseます。これにより、ページのレンダリングが遅くなる場合があります。
  2. 選択値 ( などvalue: selectedValueObservable) にバインドするための別のオブザーバブルを作成します。次に、 にサブスクライブし、optionsObservableArrayそのサブスクリプションを使用して のようなことを行いますself.selectedValueObservable(self.valueObservable())。これは応急処置のようです。
  3. サーバーからオプション データを送信することにより、javascript が実行される前に、選択とオプションをページにレンダリングします (MVC ビューモデルを使用)。これにより、オプションを として扱うのが少し難しくなりますobservableArray

アップデート

サンプルコードを単純化するために、この質問から省略した別の懸念があります。実際には、このビューモデルはデータ項目の編集可能なリストを作成するために使用されます。そのため、実際には、ページにレンダリングされるドロップダウン リストが複数あります。データ ajax 呼び出しは実際には配列を返し、その成功関数は実際にobservableArrayは複雑な項目の を設定します。ドロップダウン リスト オプションはすべてのインライン フォームで再利用されるため、$parentviewmodel に配置され、一度だけ読み込まれます。また、データ項目は WebAPI を介して取得されるため、単一の ajax 呼び出しで選択オプションを渡すことも困難です (IEnumerable追加のドロップダウン オプションを送信する余地がありません)。

4

2 に答える 2

1

最初に ajax 呼び出しを行い、applyBinding を done にしない理由はありますか?

$.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

可能であれば、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);
    });
});

2 つの ajax 呼び出しをマージできない場合は、2 番目の 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 に答える