3

エンティティのグラフに対して基本的な CRUD 操作を実行する Knockout.js アプリケーションを作成しています。サーバーから JSON でエンコードされた 2 つのオブジェクトを読み込みます。

function UploadedImage(data) {
    this.UploadedImageId = data.UploadedImageId;
    this.Url = data.Url;
    this.Name = data.Name;
    this.AltText = data.AltText;
}

...次のように、AJAX リクエストを介して ViewModel に格納されます。

$.post("@Url.Action("JsonRepairData")", {}, function (response) {
    self.repairData(_.map(response.repairData, function(d) { return new AppleProduct(d); }));
    self.images(_.map(response.images, function (i) { return new UploadedImage(i); }));
    self.dataLoaded(true);
}, 'json');

オブジェクト グラフとイメージ配列の両方で、データがすべて正しく読み込まれていることを確認しました。オブジェクト グラフ内のイメージ ID は、配列内のイメージ ID に対応します。オブジェクト グラフで関連するデータ エントリに対して選択されている画像を表示するために、次のような選択リストを選択しました。

<tbody data-bind="foreach: repairData">
    <tr>
        <td>@Html.TextBoxFor(m => m.Name, new { data_bind = "value: Name" })</td>
        <td><select data-bind="options: $root.images,  optionsCaption: 'Pick an image...', optionsValue: 'UploadedImageId', optionsText: 'Name', value: UploadedImageId"></select></td>
        <td data-bind="html: ImgTag"></td>
        <td><a href="#" data-bind="click: $root.deleteProduct">delete</a></td>
    </tr>
</tbody>

ViewModel に含まれる repairData は、前述のオブジェクト グラフであることに注意してください。他のすべてのデータは正しくバインドされます。選択ボックスが正常に表示されます。ViewModel にバインドされている UploadedImageId の値は、選択ボックスが操作されると更新されます。ただし、(オブジェクト グラフからの) UploadedImageId の ViewModel の初期値は無視され、ページがレンダリングされると、UploadImageId はすぐに undefined に更新されます。オブジェクト グラフで UploadedImageId の初期値を設定する方法は次のとおりです。

function AppleProduct(data) {
    var productSelf = this;
    this.Id = data.Id;
    this.Name = ko.observable(data.Name);
    this.UploadedImageId = ko.observable(data.UploadedImageId);
    this.Variations = ko.observableArray(_.map(data.Variations, function (v) { return new ProductSeries(v); }));
    this.ImgTag = ko.computed(function () {
        var img = _.find(self.images(), function (i) { return i.UploadedImageId == productSelf.UploadedImageId(); });
        return img ? '<img src="'+img.Url+'" />' : '';
    });
    // Remove computed ImgTag from data addressed to the server
    this.toJSON = function () {
        var copy = ko.toJS(this);
        delete copy.ImgTag;
        return copy;
    };
}

セレクトボックスを何時間も正しく設定する方法を見つけようとしてきましたが、まだ完全に困惑しています。私が判断できるのは、2.1.0 のノックアウト js ソース ファイルでは、1402 行目の選択ボックスの初期値を設定するコード (以下を参照) が 2 回渡されていることだけです。最初はモデル値がイメージ ID に適切に対応しますが、element.options.length == 0 であるため、モデル値は使用されません。このコードが 2 回目に渡されると、モデルの値はすべて未定義ですが、選択ボックスにはデータが入力されているため (つまり、element.options.length は正の数です)、適切な初期値が設定されていません。

for (var i = element.options.length - 1; i >= 0; i--) {
    if (ko.selectExtensions.readValue(element.options[i]) == value) {
        element.selectedIndex = i;
        break;
    }
}

私が欠けているものを理解するための助けがあれば大歓迎です!

4

1 に答える 1

3

nemesv が巧みに発見したように、問題は ViewModel データの母集団の順序付けでした。

$.post("@Url.Action("JsonRepairData")", {}, function (response) {
    self.repairData(_.map(response.repairData, function(d) { return new AppleProduct(d); }));
    self.images(_.map(response.images, function (i) { return new UploadedImage(i); }));
    self.dataLoaded(true);
}, 'json');

Knockout.js の依存関係の追跡は積極的であるため、システムは画像データにアクセスする前に、オブジェクト グラフ ビューにデータを入力しようとします。そのため、選択ボックスを作成しようとすると、選択ボックスに入力するデータがなく、デフォルト値を設定できません。repairData と images ViewModel データの読み込み順序を切り替えることで、必要なときに画像データが利用可能になり、アプリケーションが実行されます。

これは、ko.observables を介した Knockout.js の依存関係の追跡が強力な表現力のあるツールであるのに対し、ViewModel の状態変更に起因する意図しないロジックに適切な注意を払わないと危険になる可能性があることを示しているようです。

于 2013-11-07T14:07:55.770 に答える