2012-06-27 21 views
10

Ho il seguente CoffeeScript per generare JavaScript per KnockoutjsCoffeeScript, Knockout e osservabile

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 

Per effettuare il rendering HTML io uso questo codice

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

Tuttavia, in HTML tutti gli elementi mostrare i valori di l'ultimo NewsItem aggiunto alla collezione.

Eventuali suggerimenti?

risposta

20

Ok, questo può essere una delle insidie ​​che CoffeeScript ha:

class NewsItem 
    content: ko.observable("") 

Qui, si sta creando una nuova classe con un "contenuto" proprietà che è un oggetto osservabile. Questo compila in JavaScript il seguente:

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

Come si può vedere ora, il "contenuto" proprietà è collegata al prototipo. Ciò significa: c'è solo un osservabile creato, non uno per istanza. Pertanto, ogni volta che si esegue new NewsItem, il costruttore aggiorna questo singolo osservabile nel prototipo, quindi lo stesso valore per tutte le istanze.

Per risolvere questo, è sufficiente creare l'osservabile nel costruttore. In questo modo, si ottiene attaccato alla esempio, non il prototipo:

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

compila in (parte pertinente):

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

Credo che questo sia sempre come dovrebbe essere fatto. – Tyrsius

+0

@Tyrsius Dipende - se vuoi un membro della tua classe per ogni specifica istanza (devo essere d'accordo, lo vorrai per la maggior parte del tempo), allora sì. Hai solo bisogno di sapere la differenza. – Niko

+3

Suppongo che ci siano volte in cui vuoi una proprietà statica, ma questa dovrebbe essere l'eccezione, non la regola. – Tyrsius

Problemi correlati