I'm using Knockout.js 2.0 and I'm trying to extend the prototype of the constructor function I've created by adding a computed observable but its throwing up "self.IsSubDomain is not a function". How do I solve this error? Is there another way to extend a constructor function to solve this?
http://jsfiddle.net/StrandedPirate/J44S4/3/
Note: I know I could define the computed observable inside the constructor function's closure but I'm building an automated code generator for knockout view models and I need to be able to extend my objects through the prototype property.
I also answered this in the forum.
Here's one way to do it (jsFiddle example):
<div data-bind="text: fullDomainName">test</div>
<script>
function SiteModel(rootUrl, data) {
var self = this;
self.rootUrl = rootUrl;
self.DomainName = ko.observable(data.DomainName);
self.IsSubDomain = ko.observable(data.IsSubDomain);
self.fullDomainName = ko.computed(self.fullDomainName, self);
}
SiteModel.prototype.fullDomainName = function () {
if (this.IsSubDomain() && this.DomainName()) { // bombs out here with "self.IsSubDomain is not a function"
return this.DomainName() + ".myCompanyWebsite.com";
}
else {
return this.DomainName();
}
};
var temp = new SiteModel("someurl", { DomainName: "extraCool" });
ko.applyBindings(temp);
</script>
I've defined the function in the prototype and made it a computed
observable in the constructor.
Here's a way to do it a more generic way (jsFiddle example):
<div data-bind="text: fullDomainName">test</div>
<script>
Function.prototype.computed = function() {
this.isComputed = true;
return this;
};
Object.prototype.makeComputeds = function() {
for (var prop in this) {
if (this[prop] && this[prop].isComputed) {
this[prop] = ko.computed(this[prop], this, {deferEvaluation:true});
}
}
};
function SiteModel(rootUrl, data) {
var self = this;
self.rootUrl = rootUrl;
self.DomainName = ko.observable(data.DomainName);
self.IsSubDomain = ko.observable(data.IsSubDomain);
self.makeComputeds();
}
SiteModel.prototype.fullDomainName = function () {
if (this.IsSubDomain() && this.DomainName()) { // bombs out here with "self.IsSubDomain is not a function"
return this.DomainName() + ".myCompanyWebsite.com";
}
else {
return this.DomainName();
}
}.computed();
var temp = new SiteModel("someurl", { DomainName: "extraCool" });
ko.applyBindings(temp);
</script>
The underlying read function of the computed will be shared via the prototype
although the actual computed property won't. I suppose there could be
confusion if you created some objects and then changed the function in
the prototype. New objects would use the new function, but old objects
wouldn't.
Since computed observables are properties, you shouldn't expect to
be able to add them to existing objects through the prototype.