4

Knockoutのマッピングプラグインで奇妙な問題が発生しています。

マッピングを介して監視可能な配列を埋めると、UIが正しく更新されていても、配列を反復処理したり、その長さを取得したりできません。配列は空のように見えます。

ここで動作するjsFiddleを見つけることができます:http://jsfiddle.net/VsbsC/

これはHTMLマークアップです:

<p><input data-bind="click: load" type="button" value="Load" /></p>
<p><input data-bind="click: check" type="button" value="Check" /></p>
<table>
    <tbody data-bind="foreach: items">
        <tr>
            <td data-bind="text: name"></td>
            <td data-bind="text: value"></td>
        </tr>
    </tbody>
</table>
<p data-bind="text: total"></p>

これはJavaScriptコードです:

var ViewModel = function () {
    var self = this;
    self.items = ko.observableArray();
    self.load = function () {
        self.items([
            { "name": "joey", "value": 1 },
            { "name": "anne", "value": 2 },
            { "name": "paul", "value": 3 },
            { "name": "mike", "value": 4 }
        ]);
    };
    self.check = function () {
        alert(self.items().length);
    };
    self.total = ko.computed(function () {
        var total = 0;
        for (var i = 0; i < self.items().length; i++) {
            total += self.items()[i].value;
        }
        return total;
    });
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);

[ロード]ボタンをクリックすると、レコードと合計の両方が正しく表示され、[チェック]ボタンをクリックすると、正しいアイテム番号が表示されます。

しかし、私が変更した場合

self.items([
    { "name": "joey", "value": 1 },
    { "name": "anne", "value": 2 },
    { "name": "paul", "value": 3 },
    { "name": "mike", "value": 4 }
]);

self.items(ko.mapping.fromJS([
    { "name": "joey", "value": 1 },
    { "name": "anne", "value": 2 },
    { "name": "paul", "value": 3 },
    { "name": "mike", "value": 4 }
]));

UIは引き続き正しくレンダリングされますが、合計はゼロを示し、[チェック]をクリックするとゼロも生成され、console.info-ingを実行self.itemsすると空の配列が生成されます。

これはどのように可能ですか?チュートリアルを何度も読み直しましたが、何が間違っているのか理解できません。

Ps実際のページでは、値はAJAXリクエストから取得されているため、マッピングプラグインを介して監視可能な配列を埋める必要があります。

4

3 に答える 3

11

表示されている問題は、配列が指定されている場合、マッピング プラグインが observableArray を作成するという事実に基づいています。したがって、self.itemsobservableArray の値を (単なる配列ではなく) observableArray に等しく設定しています。そのため、余分にラップされます。

これを行う1つの方法は次のとおりです。

var ViewModel = function () {
    var self = this;
    self.items = ko.mapping.fromJS([]);
    self.load = function () {
        ko.mapping.fromJS([
            { "name": "joey", "value": 1 },
            { "name": "anne", "value": 2 },
            { "name": "paul", "value": 3 },
            { "name": "mike", "value": 4 }
        ], self.items);
    };
    self.check = function () {
        alert(self.items().length);
    };
    self.total = ko.computed(function () {
        var total = 0, items = self.items();
        for (var i = 0; i < items.length; i++) {
            total += items[i].value();
        }
        return total;
    });
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);

したがって、マッピング プラグインを使用して元の observableArray を初期化すると、更新の準備が整います。次に、更新時に、ko.mapping.fromJS更新されたデータと更新するマップされたオブジェクトを呼び出します。

その時点での他のマイナーな変更はvalue()、マッピング プラグインからのオブザーバブルであるため、計算されたオブザーバブルで使用することでした。

サンプルはこちら: http://jsfiddle.net/rniemeyer/3La5K/

于 2012-01-27T16:05:51.150 に答える
1

または、 knockout-data-projectionsを試すことができます

ビューモデルからjs配列へのマッピングを非常にうまく処理します!!

于 2012-04-24T10:42:19.480 に答える
0

items observableArray新しい値をマッピングできるように、をマッピング関数に渡す必要があります。

ここでの実用的なソリューション: http://jsfiddle.net/unklefolk/j9pdX/

self.load = function () {
    ko.mapping.fromJS([
        { "name": "joey", "value": 1 },
        { "name": "anne", "value": 2 },
        { "name": "paul", "value": 3 },
        { "name": "mike", "value": 4 }
    ], {}, self.items);
};
于 2012-01-27T16:14:18.967 に答える