Introduction
About mapping business model to Knockout observable
Background
In my app I turn my (C#) business model with JSON converter into Javascript object. Then I use ko.mapping.fromJS to turn them into observable I ran into the fact that ko.mapping is inconsistent!
(If you don't know what are observables and/or ko.mapping, have a look at Knockout)
Allow me to illustrate, say I have this C# model
class Address { string Street; }
class Person { Address Home; Address Work; }
Which I can turn into this sample JSON data
var json = { Home: null, Work: { Street: "1 work street" } }
Which after ko.mapping will become
var kojson = ko.mapping.fromJS(json)
var json = { Home: ko.observable(), Work: { Street: ko.observable("1 work street") } }
See the problem? Home
is now an observable property, whereas Work
is a normal object (with observable properties)
Using the code
To solve this problem I wrote a replacement function, here is the (TypeScript) version
function komapperToKO(src) {
var mapped: Array<{ src; dst; }> = [];
var map = function (obj) {
obj = ko.unwrap(obj);
if (obj === null
|| obj === undefined
|| typeof obj === "number"
|| typeof obj === "boolean"
|| typeof obj === "string"
|| typeof obj === "function"
) {
return obj;
}
else if (obj instanceof Array) {
var ares = [];
for (var i = 0; i < obj.length; i++) {
ares.push(map(obj[i]));
}
return ko.observableArray(ares);
}
else {
var prev = mapped.enumerable().first(x => x.src === obj);
if (prev)
return prev.dst;
var res = <any>{};
mapped.push({ src: obj, dst: res });
for (var p in obj) {
var pv = ko.unwrap(obj[p]);
if (typeof pv === "function") {
res[p] = pv;
}
else if (pv instanceof Array) {
res[p] = map(pv);
}
else {
res[p] = ko.observable(map(pv));
}
}
return res;
}
}
return map(src);
}
Points of Interest
A little dive inside Knockout
History
Keep a running update of any changes or improvements you've made here.
The Australia born French man who went back to Australia later in life...
Finally got over life long (and mostly hopeless usually, yay!) chronic sicknesses.
Worked in Sydney, Brisbane, Darwin, Billinudgel, Darwin and Melbourne.