Are prototype observables calculated in KnockoutJS?

I have an array of items returned from a service. I am trying to determine the calculated observable for each instance of the element, so my instinct tells me to put it in the prototype.

One case for a calculated observable: the system calculates the points, but the user can choose to override the calculated value. I need to save the calculated value in case the user removes the override. I also need to combine the user assigned and calculated points and summarize the totals.

I use matching to do the following:

var itemsViewModel; var items = [ { 'PointsCalculated' : 5.1 }, { 'PointsCalculated' : 2.37, 'PointsFromUser' : 3 } ]; var mapping = { 'Items' : { create : function(options) { return new Item(options.data); } } }; var Item = function(data) { var item = this; ko.mapping.fromJS(data, mapping, item); }; Item.prototype.Points = function () { var item = this; return ko.computed(function () { // PointsFromUser may be 0, so only ignore it if the value is undefined/null return (item.PointsFromUser != null) ? item.PointsFromUser : item.PointsCalculated; }); }; ko.mapping.fromJS(items, mapping, itemsViewModel); 

Now, how this works, I have to call an anonymous function to return the computed observable. It seems that a new instance of the computed observable is created for each binding, which affects most of the point placing it in the prototype. And it's a little annoying to decipher how many parentheses to use each time I access the observable.

It is also somewhat fragile. If I try to access Points () in code, I cannot do

 var points = 0; var p = item.Points; if (p && typeof p === 'function') { points += p(); } 

because it changes in the context of Points () to a DOMWindow, not an element.

If I put the computed in create () in the mapping, I could capture the context, but then there is an instance of the method for each instance of the object.

I found the post by Michael Best Google Groups ( http://groups.google.com/group/knockoutjs/browse_thread/thread/8de9013fb7635b13 ). The prototype returns a new computed observable “activate”. I did not understand what causes “activate” (maybe Objs?), But I suppose that this happens once for the object anyway, and I don’t know how much 'this' will get.

At this stage, I believe that I have passed by what is available in the published documents, but I am still working on deciphering what comes from the source.

+6
source share
3 answers

You mentioned that you do not want to have an instance of the ko.computed function for every instance of your javascript class, however this will not work with how the ko functionality was created. When you use ko.computed or ko.observable , they create certain pointers to private variables inside, in which you usually do not want to share between class instances (although in rare cases you could).

I am doing something like this:

 var Base = function(){ var extenders = []; this.extend = function(extender){ extenders.push(extender); }; this.init = function(){ var self = this; // capture the class that inherits off of the 'Base' class ko.utils.arrayForEach(extenders, function(extender){ // call each extender with the correct context to ensure all // inheriting classes have the same functionality added by the extender extender.call( self ); }); }; }; var MyInheritedClass = function(){ // whatever functionality you need this.init(); // make sure this gets called }; // add the custom base class MyInheritedClass.prototype = new Base(); 

then for computed observables (which should be instance functions for each instance of your MyInheritedClass ), I simply declare them in extender as follows:

 MyInheritedClass.prototype.extend(function(){ // custom functionality that i want for each class this.something = ko.computed(function() { return 'test'; }); }); 

Given your example and the Base class defined above, you can easily do:

 var Item = function(data) { var item = this; ko.mapping.fromJS(data, mapping, item); this.init(); // make sure this gets called }; Item.prototype = new Base(); Item.prototype.extend(function () { var self = this; this.Points = ko.computed(function () { // PointsFromUser may be 0, so only ignore it if the value is undefined/null return (self.PointsFromUser != null) ? self.PointsFromUser : self.PointsCalculated; }); }; 

Then all instances of your Item class will have the Points property and will correctly process the ko.computed logic for each instance.

+7
source
 Item.prototype.Points = function () { var item = this; return ko.computed(function () { // PointsFromUser may be 0, so only ignore it if the value is undefined/null return (item.PointsFromUser != null) ? item.PointsFromUser : item.PointsCalculated; }); 

};

0
source
 Item.prototype.extend(function () { var scope = this this.Points = ko.computed(function () { return (this.PointsFromUser != null) ? this.PointsFromUser : this.PointsCalculated; }, scope); }; 
0
source

Source: https://habr.com/ru/post/914042/


All Articles