1

顧客注文と多くの注文項目をモデル化する KnockoutJS ビューモデルを作成しようとしています。初期データをロードし、データを検証したいと考えています。

これまでのところ、knockoutjs.mapping を使用してデータをロードし、マッピングを使用して追加されたデータを検証できます。

// data to load into viewmodel
var modeldata = {
  "OrderID":1,
  "ReturnString":null,
  "CustomerName":"First Customer",
  "OrderDate":"2013-09-16T19:41:40.1639709+01:00",
  "OrderItems": [
     {"ItemID":0,
      "ItemName":"Name_0",
      "ItemPrice":0.0,
      "_destroy":false
     },
     {"ItemID":1,
      "ItemName":"Name_1",
      "ItemPrice":10.0,
      "_destroy":false
     },
     {"ItemID":2,
      "ItemName":"Name_2",
      "ItemPrice":20.0,
      "_destroy":false
     }
   ]
};


// setup defaults for validation
var validationOptions = {
    insertMessages: true,
    decorateElement: true,
    errorElementClass: 'errorCSS',
    messagesOnModified: true,
    debug: true,
    grouping: {
        deep: true,
        observable: false //Needed so added objects AFTER the initial setup get included
    },
};

ko.validation.init(validationOptions);


// define array model
var Item = function () {
    var self = this;
    ItemID = ko.observable();
    ItemName = ko.observable().extend({
      required: { message: '* item name needed' }
    });
    ItemPrice = ko.observable();
    _destroy = false;
}

// define view model
var ViewModel = function (data) {
    var self = this;
    self.OrderID = ko.observable();
    self.ReturnString = ko.observable();
    self.CustomerName = ko.observable().extend({
      required: { message: '* customer name needed' }
    });
    self.OrderDate = ko.observable();
    self.OrderItems = ko.observableArray([]);  // to be array of "Item"

    // create validation group
    self.orderErrors = ko.validation.group(self);
    self.orderItemErrors = ko.validation.group(
      self.OrderItems, { deep: true }
    );

    self.lineItemsValid = function () {
        var LValid = false;
        if (self.orderItemErrors().length > 0) {
            if (self.orderItemErrors()[0] != null) // important to test for null
                LValid = false;
            else 
                LValid = true;
            }
        else  LValid = true 
        if (LValid) {
            return true
            }
        else
            {
            self.orderItemErrors.showAllMessages();
            return false;
            }
    }

    self.orderValid = function () {
        var LValid = false;
        if (self.orderErrors().length > 0) {
            if (self.orderErrors()[0] != null) // important to test for null
                LValid = false;
            else
                LValid = true;
        }
        else LValid = true
        if (LValid) {
            return true
        }
        else {
            self.orderErrors.showAllMessages();
            return false;
        }
    }

    self.isValid = function () {
        if(self.orderValid() & self.lineItemsValid()){
        alert('All ok!')
        }
        else{
        alert('Errors!');}
    }


    // operations
    self.addLineItem = function () {
        self.OrderItems.unshift(new Item());
    }

    self.removeLineItem = function (item) {
        self.OrderItems.destroy(item);
    }

    // load data into model
    self.loadData = function () {
        ko.mapping.fromJS(modeldata, {}, self);
    }


}

$(document).ready(function () {
    var viewModel = new ViewModel()
    ko.applyBindings(viewModel);
});

問題:

(1) クリック機能を使用して注文項目を追加することもできますが、これらのデータは監視可能な配列で更新されないようです。ただし、「削除」項目関数を呼び出すと、配列項目が削除済みとしてマークされます。

(2) マッピングを使用してアイテムをロードし、検証をテストすると (required = true)、マッピングが完了した後に追加した注文アイテムではなく、マッピングを介してロードされたアイテムに対してのみ機能します

(3)マッピングによって持ち込まれた注文アイテムを更新すると、変更はすぐにオブザーバブル配列に反映され、マッピング後に追加した注文アイテムを更新すると、配列に更新がありません。

私はここに JSFiddle を持っています:

http://jsfiddle.net/devops/ZsDjh/40/

観測可能な配列に追加する方法に関係していると確信していますが、明らかなものは何も見えません-明らかに基本的なものが欠けています...誰かアイデアがあれば?

ありがとう

4

1 に答える 1

9

ほんの少しの見落としがあります。

まずは(3)に飛びます

(3) マッピングによって持ち込まれた注文項目を更新すると、その変更はすぐにオブザーバブル配列に反映され、マッピング後に追加した注文項目を更新すると、配列に更新がありません。

Item 関数では、プロパティをthis (self)にバインドする必要があります。

var Item = function () {
    var self = this;
    self._destroy = false;
    self.ItemID = ko.observable();
    self.ItemName = ko.observable().extend({ required: { message: '* item name needed' } });
    self.ItemPrice = ko.observable();
}

(2)については、

(2) マッピングを使用してアイテムをロードし、検証をテストすると (required = true)、マッピングが完了した後に追加した注文アイテムではなく、マッピングを介してロードされたアイテムに対してのみ機能します

これは、マッピング プラグインを使用する方法と、OrderItems observableArray に新しいアイテムを追加する方法が原因です。

// load data into model
self.loadData = function () {
    ko.mapping.fromJS(modeldata, {}, self);
}

あなたのフィドルからこれを複製することはできませんでしたが、何が起こっているのかについて非常に良い考えを持っています.

マッピングのプラグインは、JSON から監視可能なプロパティを作成し、自分自身にプロパティをそれぞれ割り当てる (またはあなたの場合は再割り当てする)だけであるため、配列内の各OrderItemsオブジェクトが新しい Item()オブジェクトになることはわかりません。匿名の監視可能なオブジェクトを作成し、それらを新しい observableArray に配置してから、それをself.OrderItemsに割り当てているだけです。

配列の処理方法をマッパーに指示する必要があります。

// outside your viewmodel
var itemMapping = {
    create: function (options) {
        return new Item(options.data);
    }
};

// load data into model
self.loadData = function () {
    ko.mapping.fromJS(modeldata, { OrderItems: itemMapping }, self);
}

ここで、JSON 配列の各アイテムをitemMappingのcreate関数に渡します。しかし、私たちは今問題を抱えています。Item 関数はパラメーターを取りません。それでは、それを修正しましょう。そして、その間、マッパーにItemの監視可能なプロパティを作成するのを手伝ってもらいましょう。

var Item = function (data) {
    var self = this;
    self._destroy = false;
    //self.ItemID = ko.observable(data.ItemID);
    //self.ItemName = ko.observable(data.ItemName).extend({ required: true });
    //self.ItemPrice = ko.observable(data.ItemPrice);
    ko.mapping.fromJS(data, {}, self);
    self.ItemName.extend({ required: { message: '* item name needed' } });
}

Item 関数を変更したので、 addLineItemメソッドを更新する必要があります。

// operations
self.addLineItem = function () {
    // set the default values
    self.OrderItems.unshift(new Item({ ItemId: null, ItemName: "", ItemPrice: 0 }));
}

ここで、self.lineItemsValidおよびself.orderValidメソッドを取り除き、self.orderItemErrorsプロパティを削除します。

isValidメソッドの名前を変更して更新します。

self.checkValid = function () {
    if(self.isValid()){
      alert('All ok!');
    }
    else{
      self.orderErrors.showAllMessages();
    }
}

self.isValid()は、検証プラグインによって作成されるメソッドです。あなたはそれを上書きしていました。

そして、html を更新します。

<a href="#" data-bind="click: checkValid">Check is valid</a>

最後に (1)、

(1) クリック機能を使用して注文項目を追加することもできますが、これらのデータは監視可能な配列で更新されないようです。

これは、 Item関数に加えた変更により修正されました。

ただし、「削除」項目関数を呼び出すと、配列項目が削除済みとしてマークされます。

完全に削除するか、単に_destroyedというラベルを付けるかはわかりません。

単に削除したい場合は、removeLineItemメソッドを更新してください。

self.removeLineItem = function (item) {
    self.OrderItems.remove(item);
}

Observable Arrayに関するノックアウト ドキュメントを参照し、remove メソッドと destroy メソッドについて読んで、最適なものを判断してください。

これが変更された jsFiddleです。

乾杯!

PSこの答えがあなたの車輪に油を注いだので+1してください!:)

于 2013-09-25T20:34:29.927 に答える