How do I add a computed property via the prototype?

686 views
Skip to first unread message

StrandedPirate

unread,
Apr 23, 2012, 5:28:31 PM4/23/12
to KnockoutJS
I've got a model that I want to later extend with a computed variable
but it is throwing errors.

Here is my model:

function SiteModel(rootUrl, data) {
var self = this;
self.rootUrl = rootUrl;
self.DomainName = ko.observable(data.DomainName);
self.IsSubDomain = ko.observable(data.IsSubDomain);
}

Later on I'm trying to extend SiteModel but it bombs out saying
"IsSubDomain is not a function". Is this even possible? I know I could
put the fullDomainName inside the SiteModel closure but I'm trying
some automation so I need to be able to extend the model's prototype
after its defined.

SiteModel.prototype.fullDomainName = ko.computed(function () {
return (self.toString()); // returns the window object...
if (this.IsSubDomain() && this.DomainName()) { // bombs
out here
return this.DomainName() + ".myCompanyWebsite.com";
}
else {
return this.DomainName();
}
}, this);

StrandedPirate

unread,
Apr 23, 2012, 6:24:30 PM4/23/12
to KnockoutJS
Here is a fiddle showing the issue: http://jsfiddle.net/StrandedPirate/J44S4/2/

Bob Lauer

unread,
Apr 25, 2012, 9:14:27 AM4/25/12
to knock...@googlegroups.com
I tried to get this working using prototype, but I can't, and I'm not sure it's even possible.  

The advantage of adding a function to the SiteModel's prototype property is that it will be shared across all instances of the SiteModel.  However, if you're only going to have one instance of the SiteModel, then that advantage doesn't really come into play.  If that's the case, you can do something like this:

var model = new SiteModel("someUrl", someDataObject);
model.fullDomainName = ko.computed(function() {
   // Do something in here
}, model);

Just make sure you pass in model as the 2nd parameter to ko.computed, which will set the "this" variable to your model object inside of your function that you passed to ko.computed.

rpn

unread,
Apr 25, 2012, 9:54:42 AM4/25/12
to knock...@googlegroups.com
observables and computed observables are functions that store some state internally, which means that they can't really be put on the prototype like a normal function or property could.

I have seen some people create functions on the prototype that add observables to the instance and then call some kind of "init" when the object is created to call these functions.

Michael Best

unread,
Apr 25, 2012, 8:54:15 PM4/25/12
to KnockoutJS
Here's one way to do it: http://jsfiddle.net/mbest/J44S4/29/

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: http://jsfiddle.net/mbest/XEez7/

-- Michael

On Apr 23, 12:24 pm, StrandedPirate <joey_brads...@strandedpirate.com>
wrote:

Bob Lauer

unread,
Apr 25, 2012, 9:07:11 PM4/25/12
to knock...@googlegroups.com
Both are clever solutions.

It's worth noting that the above methods have three drawbacks though:

1. It extends Object.prototype.  This is widely considered bad practice.  Here's a blog post about why not to do that.  I will admit that this can be worked around very easily, but thought it was still worth mentioning.
2. The nice part about functions that are added to the prototype object is that only one function exists across all instances, instead of each instance having its own copy of the function.  In this case, however, a copy of the observable function will be created for each instance of the SiteModel that is instantiated.
3. The other nice part about functions that are added to the prototype object is all instances of the object will be able to use them, even if those instances were instantiated before the method was added to the prototype object.  However, all methods added to the SiteModel.prototype will not be converted to computed functions on all already-existing instances of SiteModel, since that conversion happens in the constructor.  Depending on when you define the function on the prototype object and when you instantiate your object, you may or may not have that computed function available on your object.

Truthfully, I don't see any advantage to defining functions on the prototype.  You end up creating copies of the function anyway, and you just make your code more confusing.

Michael Best

unread,
Apr 25, 2012, 9:31:04 PM4/25/12
to KnockoutJS
Bob, good points. Computed observables should be treated like
properties of an object instance rather than methods of the object.
But since they are defined via a function, the prototype is a
convenient place to put those functions. In response to your points:

1. I don't extend Object in my own code, but it was a convenient way
to demonstrate it. Thanks for pointing that out.

2. The underlying read function of the computed *will* be shared
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.

3. Since computed observables are properties, you shouldn't expect to
be able to add them to existing objects through the prototype.

Thanks,
Michael
Reply all
Reply to author
Forward
0 new messages