2012-06-27 23 views
10

Mam następujący coffeescript wygenerować Javascript dla Knockoutjscoffeescript, Knockout & obserwowalne

class NewsItem 
    content: ko.observable("") 
    title: ko.observable("") 

    constructor: (data,dispForm) -> 
     @content data.get_item("content") 
     @title data.get_item("title") 
     @id = data.get_id() 

class NewsItemViewModel 
    collection: ko.observableArray() 

    loadAll: => 
      listEnumerator = items.getEnumerator()   
      while listEnumerator.moveNext() 
       currentItem = listEnumerator.get_current() 
       @collection.push new NewsItem currentItem, @list.get_defaultDisplayFormUrl() 
      return 

$ -> 
    viewModel = new NewsItemViewModel 
    ko.applyBindings viewModel 
    return 

Do renderowania HTML mogę użyć tego kodu

<ul id="results" data-bind="template: {name: 'item_template', foreach: collection}"> 
</ul> 
<script id="item_template" type="text/x-jquery-tmpl"> 
<li> 
    <h3><a href="/" data-bind="text: title"></a></h3> 
    <p> 
     <textarea data-bind="value: content"></textarea> 
     <input type="button" value="save" data-bind="enable: content().length > 0"> 
    </p> 
</li> 
</script> 

Jednak w HTML wszystkie elementy pokazują wartości ostatnia NewsItem dodana do kolekcji.

Jakieś wskazówki?

Odpowiedz

20

Ok, może to być jedna z pułapek, które coffeescript posiada:

class NewsItem 
    content: ko.observable("") 

Tutaj tworzymy nową klasę z właściwością „treści”, która jest obserwowalny przedmiot. Kompiluje się w następujący kod JavaScript:

var NewsItem = (function() { 
    function NewsItem() {} 
    NewsItem.prototype.content = ko.observable(""); 
    return NewsItem; 
})(); 

Jak widać, właściwość "treść" jest dołączona do prototypu. Oznacza to, że istnieje tylko jeden możliwy do zaobserwowania, a nie jeden na instancję. Tak więc za każdym razem, gdy wykonujesz new NewsItem, konstruktor aktualizuje ten pojedynczy obserwowany w prototypie, stąd ta sama wartość dla wszystkich instancji.

Aby rozwiązać ten problem, wystarczy utworzyć obserwowalne w konstruktorze. W ten sposób, to get dołączone do instancji, a nie prototyp:

class NewsItem 
    constructor: (data,dispForm) -> 
     @content = ko.observable data.get_item("content") 

kompiluje (w odpowiedniej części):

this.content = ko.observable(data.get_item("content")); 
+0

myślę, że to jest zawsze jak to powinno być zrobione. – Tyrsius

+0

@Tyrsius To zależy - jeśli chcesz mieć własnego członka klasy dla każdej konkretnej instancji (muszę się zgodzić, będziesz tego potrzebował przez większość czasu), to tak. Trzeba tylko poznać różnicę. – Niko

+3

Przypuszczam, że czasami będą potrzebne właściwości statyczne, ale powinien to być wyjątek, a nie reguła. – Tyrsius