I am creating an observable array from JSON data. Either I am creating the viewmodel wrong initially or I am adding new data to the array incorrectly. When I console.log out the array after adding to it, the newly added data is different.
Here is a screenshot:
As you can see the object after brocCode=1800 is different than all the previous items in the array. I think the issue is that when I am adding a new line to the table, I am creating a new itemModel and adding that to the items list. When I am getting the JSON data and making that an observable array, I am not making an observable array of itemModels.
Here is my KnockoutJS: (specifically look at the self.addLine function and self.items = ko.observableArray(items); in itemsModel):
var itemModel = function (data) {
var self = this;
self.invalidItem = ko.observable(true);
self.itemNo = ko.observable(data ? data.itemNo : '').extend( {
required: {
params: true,
message: "Item no. required."
}
});
self.brocCode = ko.observable(data ? data.brocCode : '').extend( {
required: {
params: true,
message: "Bro code required."
}
});
self.itemDesc = ko.observable(data ? data.itemDesc : '').extend( {
required: {
params: true,
message: "Item desc required."
}
});
self.retail = ko.observable(data ? data.retail : '').extend( {
required: {
params: true,
message: "Retail required."
}
})
.extend({numeric: 2});
self.prizeNum = ko.observable(data ? data.prizeNum : '').extend( {
required: {
params: true,
message: "Prize num required."
}
});
self.itemOrder = ko.observable(data ? data.itemOrder : '').extend( {
required: {
params: true,
message: "Item order required."
}
});
}
var itemsModel = function(items) {
var self = this;
self.items = ko.observableArray(items);
//self.items = ko.mapping.fromJSON(items, itemModel);
self.invalidItem = ko.observable(true);
self.checkItemNo = function(data) {
//console.log("lost focus - " + self.invalidItem());
var itemNo = $.trim(data.itemNo());
console.log(itemNo);
if (itemNo != "") {
var item = "";
$.each(window.listOfItems, function(i, v) {
if (v.No.search(itemNo) != -1) {
item = v.Description;
return;
}
});
console.log(item);
if(item != "") {
console.log(self.items());
var match = ko.utils.arrayFirst(self.items(), function(newItem) {
console.log("checking " + newItem.itemNo);
return itemNo === newItem.itemNo;
});
console.log("match: " + match);
if (!match) {
data.itemDesc(item);
} else { // item already entered
data.invalidItem(true);
setTimeout(function() { data.invalidItem(true); }, 1);
data.itemDesc("");
slideDownMsg("Item already entered.");
slideUpMsg(3000);
}
} else { // invalid item #
console.log(data);
data.invalidItem(true);
setTimeout(function() { data.invalidItem(true); }, 1);
data.itemDesc("");
slideDownMsg("Invalid item number.");
slideUpMsg(3000);
}
}
}
self.submit = function() {
//self.showErrors(true);
if (viewModel.errors().length === 0) {
console.log('Thank you.');
$("#brochureForm").submit();
}
else {
console.log('Please check your submission.');
viewModel.errors.showAllMessages();
$(".input-validation-error").first().focus();
}
}
self.addLine = function() {
var iModel = new itemModel();
iModel.invalidItem(true);
self.invalidItem(true);
console.log("adding new line; it is: " + self.invalidItem());
self.items.push( iModel );
//setTimeout(function() { self.invalidItem(true); }, 1);
};
self.insertLine = function(index) {
self.items.splice(index, 0, new itemModel() );
};
self.removeItem = function(item) {
self.items.remove(item);
};
self.errors = ko.validation.group(self.items, { deep: true, live: true });
self.validate = function() {
self.errors.showAllMessages();
}
};
var profitCode = function(code, desc, name) {
this.code = code;
this.desc = desc;
this.name = name;
};
var codeModel = function(codes) {
var self = this;
self.availableProfitCodes = ko.observableArray([])
self.codes = ko.observableArray(codes);
}
var profitItemsModel = function(items) {
var self = this;
self.items = ko.observableArray(items);
}
var combined = (function () {
function combinedVM() {
this.codes = ko.observable(codeModel);
this.items = ko.observable(profitItemsModel);
this.availableProfitCodes = codeModel.availableProfitCodes;
}
return combinedVM;
})();
ko.bindingHandlers.enterPress = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var allBindings = allBindingsAccessor();
element.addEventListener('keydown', function (event) {
var keyCode = (event.which ? event.which : event.keyCode);
if (keyCode === 13 || (!event.shiftKey && keyCode === 9)) {
event.preventDefault();
//bindingContext.$root.invalidItem(false);
bindingContext.$root.addLine();
return false;
}
return true;
});
}
};
ko.bindingHandlers.insertPress = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var allBindings = allBindingsAccessor();
element.addEventListener('keydown', function (event) {
var keyCode = (event.which ? event.which : event.keyCode);
if (keyCode === 45) {
event.preventDefault();
bindingContext.$root.insertLine(ko.unwrap(valueAccessor()));
return false;
}
return true;
});
}
};
ko.bindingHandlers.selected = {
update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var selected = ko.utils.unwrapObservable(valueAccessor());
if (selected) element.select();
}
};
function GetItems() {
var itemsJSON = @Html.Raw(Json.Encode(Model.brochureItems));
viewModel = new itemsModel(itemsJSON);
ko.applyBindings(viewModel, $("#itemListContainer")[0]);
}
GetItems() gets called on Document.ready.
ko.mapping.fromJS()in order to have all the properties in your existingitemsJSONconverted intoko.observable(). Tryvar itemsJSON = ko.mapping.fromJS(@Html.Raw(...))(you may need to install the mapping plugin: knockoutjs.com/documentation/plugins-mapping.html)Error: The argument passed when initializing an observable array must be an array, or null, or undefined.ko.observableArray(items.map(function(data) { return new itemModel(data) }));