2012-04-24 8 views
6

Mam szereg przedmiotów wracających z usługi. Próbuję zdefiniować obliczenie obserwowalne dla każdej instancji elementu, więc mój instynkt podpowiada mi, aby umieścić go na prototypie.Czy obliczalne obserwowalne na prototypach są możliwe w KnockoutJS?

Jeden przypadek dla obliczonego obserwowalnego: system oblicza punkty, ale użytkownik może wybrać przesłonięcie obliczonej wartości. Muszę zachować obliczoną wartość dostępną na wypadek, gdyby użytkownik usunął przesłonięcie. Muszę również połączyć punkty przypisane przez użytkownika i obliczone oraz sumować sumy.

Używam mapowanie wykonać następujące czynności:

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); 

Jak to działa teraz, muszę wywołać funkcję anonimową do zwrotu obliczana obserwowalne. To wydaje się tworzyć nową instancję obliczanego obserwowalnego dla każdego wiązania, które pokonuje większość punktu umieszczenia go na prototypie. I jest to trochę denerwujące, gdy trzeba odcyfrować ile nawiasów użyć, ilekroć uzyskuję dostęp do obserwowalnego.

Jest również nieco kruchy. Jeśli próbuję Punkty dostępowe() w kodzie, nie mogę zrobić

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

dlatego, że zmienia się kontekst Punktów(), aby DOMWindow, zamiast elementu.

Jeśli umieściłem obliczone w create() w mapowaniu, mogę przechwycić kontekst, ale istnieje kopia metody na każdej instancji obiektu.

Znalazłem post Google Groups dla Michaela Besta (http://groups.google.com/group/knockoutjs/browse_thread/thread/8de9013fb7635b13). Prototyp zwraca nowe obliczone obserwowalne na "aktywuj". Nie domyśliłem się, co nazywa się "aktywować" (może Objs?), Ale przypuszczam, że zdarza się to jeszcze raz na obiekt i nie mam pojęcia, jaki zasięg uzyska "to".

W tym momencie uważam, że przeszłam to, co jest dostępne w opublikowanych dokumentach, ale wciąż pracuję nad rozszyfrowaniem tego, co dzieje się ze źródła.

Odpowiedz

7

Podkreślasz, że nie chcesz mieć instancji funkcji ko.computed dla każdej instancji klasy javascript, która jednak nie będzie działać z budową funkcji ko. Podczas korzystania z ko.computed lub ko.observable tworzone są specjalne wskaźniki pamięci dla zmiennych prywatnych wewnątrz, które normalnie nie powinny być współużytkowane w instancjach klasy (chociaż w rzadkich przypadkach można).

zrobić coś takiego:

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(); 

następnie dla obserwabli komputerowej (które mają być funkcje instancji w każdej instancji swojej MyInheritedClass) Ja po prostu zadeklarować je w extender tak:

MyInheritedClass.prototype.extend(function(){ 

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

Biorąc swój przykład i klasa Base zdefiniowano powyżej, można łatwo zrobić:

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; 
    }); 
}; 

Następnie wszystkie wystąpienia klasy Item będą miały właściwość Points i będą prawidłowo obsługiwać logikę ko.computed dla każdego wystąpienia.

+0

Dzięki. Wydaje mi się, że właśnie został użyty .extend(). To rozwiązuje dobrze moje problemy związane z wywoływaniem funkcji podwójnej funkcji, i powiem ci, że Knockout nie pozwoli mi utrzymać faktycznego obliczenia obserwowalnego na prototypie. –

+0

eric, czy mógłbyś podać bardziej "skażoną" wersję? Coś w stylu childClass = BaseClass.extend (function() {/*...*/}), które już wykonuje konfigurację łańcucha prototypów? Zrobić to ręcznie dla każdej instancji klasy jest nieco dziwne ... – fbuchinger

+0

Nie widzę żadnego powodu, dla którego nie można umieścić funkcji statycznej "rozszerzania" na dziedziczonym konstruktorze, o ile w zasadzie to robi: ' SubClass.extend = function (extender) {SubClass.prototype.extend (extender); }; ' – ericb

0
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
Item.prototype.extend(function() { 
var scope = this 
this.Points = ko.computed(function() { 
    return (this.PointsFromUser != null) ? 
      this.PointsFromUser : this.PointsCalculated; 
}, scope); 
}; 
Powiązane problemy