When creating a viewmodel for Knockout, what’s the difference here? I see these different implementations and I’ve tried a few and some don’t work the same.
//the most common example.
function ViewModel(data){
data = data || {}; var self = this; //note self = this
self.property1 = ko.observable(data.property1 || null);
}
//this one uses a var
var ViewModel = function(data) {
data = data || {}; var self = this; //note self = this
self.property1 = ko.observable(data.property1 || null);
}
//this one uses a var, returns itself, and self isn't "this"
var ViewModel = function(data){
data = data || {}; var self = {}; //note self is empty object
self.property1 = ko.observable();
if (data.property1){self.update(data);};
self.update = function(){self.property1 = data.property1 || null);};
return self;
}
I’ve noticed that with the second model, I’ve had troubles trying to reference $parent in the data-binding part of HTML. The only one that seems to work reliably for it is the last model (and I understand the .update bit, allows you to refresh the viewmodel as well).
Is there a real difference here? I’ve only noticed that with the last example, if I replace self = {}
with self=this
, I get issues with $parent and such in the data-binding in HTML (admittedly, my viewmodel was much more complex, built from multiple observablearrays of observables). I also remember having problems with computed functions not showing up based on the type I used. It was all very confusing (and hard to debug a ko’d object’s structure, functions everywhere!).
Here’s what I ended up doing:
//this is the "main" viewmodel, what gets .applyBindings()'d
var FulfillRequistionRequestModel = function (data) {
data = data || {}; var self = {};
self.RequisitionId = ko.observable(data.RequisitionId || null);
self.FulfillItemList = ko.observableArray(
ko.utils.arrayMap(data.FulfillItemList, function (item_list) { return new FulfillItemModel(item_list); })
);
self.NumberOfItems = ko.computed(function () { return self.FulfillItemList().length; });
//add-remove FullfillItem in FulfillItemList (this is per line number)
self.removeItemFromList = function (fulfill_item) { self.FulfillItemList.remove(fulfill_item); };
self.addItemToList = function () { self.FulfillItemList.push(new FulfillItemModel()); };
//allow self updates
self.update = function (data) {
data = data || {};
self.FulfillItemList.removeAll(); self.RequisitionId(data.RequisitionId || null);
if (data.FulfillItemList) {
$.each(data.FulfillItemList, function (i, item) {
self.FulfillItemList.push(new FulfillItemModel(item));
});
}
}; if (data) { self.update(data); } //this handles first-construction (.applyBinding)
return self;
};
//an observable (array'd in main vm)
var FulfillItemModel = function (data) {
data = data || {}; var self = {};
self.BoxNumber = ko.observable(data.BoxNumber || null);
self.LineNumber = ko.observable(data.LineNumber || null);
self.SourceBin = ko.observable(new BinModel(data.SourceBin) || null);
self.ItemDetailList = ko.observableArray(
ko.utils.arrayMap(data.ItemDetailList, function (item_list) { return new ItemDetailModel(item_list); })
);
self.NumberOfItems = ko.computed(function () {return self.ItemDetailList().length;});
//add-remove something from ItemDetailList (ItemDetail)
self.removeItemFromList = function (item) { self.ItemDetailList.remove(item); };
self.addItemToList = function () { self.ItemDetailList.push(new ItemDetailModel()); };
return self;
};
//an observable two deep
var ItemDetailModel = function(data) {
data = data || {}; var self = {};
self.Part = ko.observable(data.Part || null);
self.Owner = ko.observable(data.Owner || null);
self.Condition = ko.observable(data.Condition || null);
self.Bcn = ko.observable(data.Bcn || null);
self.SerialNumber = ko.observable(data.SerialNumber || null);
self.Quantity = ko.observable(data.Quantity || null);
return self;
};
TLDR: So I guess what I’m wondering, without really knowing enough about how JS works (I know enough to do damage, plus 10 more damage – but not how it operates internally, or prototyping, etc). What’s the best choice for this?
The reason I use .update, is because I like being able to refresh the whole model (think looking at a customer and all their orders and their clients, etc) – and choosing customers on the fly from a list. ko.mapping
makes this easy, not so much when you build it out. This way, I can just var myModel = new ViewModel(data);
or later do a myModel.update(new_data);
. (i know there’s a ko.extend feature — but I never got that to work right, even trying RP’s example).
4