2012-12-21 32 views
9

Ich habe 3 beobachtbare Variablen im View-Modell, und möchte auf formatierten Wert ausgeben. Ich möchte jedoch nicht für jede von ihnen eine berechnete Methode schreiben, da sie identisch sind. Was ist der beste Weg, den Code wiederzuverwenden? Vielen Dank.Erstellen Sie eine berechnete Observable für formatierte Werte für eine Reihe von Variablen

Der Code, den ich erreichen werde, ist:

this.formattedPrice = ko.computed({ 
     read: function() { 
      return '$' + this.price().toFixed(2); 
     }, 
     write: function (value) { 
      // Strip out unwanted characters, parse as float, then write the raw data back to the underlying "price" observable 
      value = parseFloat(value.replace(/[^\.\d]/g, "")); 
      this.price(isNaN(value) ? 0 : value); // Write to underlying storage 
     }, 
     owner: this 
    }); 

Und das ausgefallene Beispiel ist in: Jsfiddle

Danke,

Antwort

17

Hier sind ein paar Möglichkeiten, wie Sie diese wiederverwendbar zu machen.

Wenn Sie dies in Ihrem Ansichtsmodell handhaben möchten, ist es eine gute Wahl, eine Erweiterung zu erstellen, die das formatierte, berechnete Observable als "Unterbeobachtungsobjekt" Ihres Originals speichert. Sie können Observables unter Verwendung von extenders oder durch Hinzufügen zum gemeinsamen Objekt fn wie beschrieben here erweitern. Ich bevorzuge Letzteres.

So könnten Sie Observablen eine Funktion hinzufügen, die withCurrencyFormat genannt wird. Es könnte wie folgt aussehen:

ko.observable.fn.withCurrencyFormat = function(precision) { 
    var observable = this; 
    observable.formatted = ko.computed({ 
     read: function (key) { 
      return '$' + (+observable()).toFixed(precision); 
     }, 
     write: function (value) { 
      value = parseFloat(value.replace(/[^\.\d]/g, "")); 
      observable(isNaN(value) ? null : value); // Write to underlying storage 
     }   
    }); 

    return observable; 
}; 

Jetzt können Sie sagen:

self.week1Amount = ko.observable(w1).withCurrencyFormat(2); 
self.week2Amount = ko.observable(w2).withCurrencyFormat(2); 
self.week3Amount = ko.observable(w3).withCurrencyFormat(2); 

und binden dagegen in der Benutzeroberfläche wie:

<td><input data-bind="value: week1Amount.formatted" /></td> 
    <td><input data-bind="value: week2Amount.formatted" /></td> 
    <td><input data-bind="value: week3Amount.formatted" /></td> 

Beispiel hier: http://jsfiddle.net/rniemeyer/xskJN/

Another Die Wahl besteht darin, diese in eine Bindung zu verschieben, sodass Sie Ihr Ansichtsmodell in Ruhe lassen können. Dies würde einen ähnlichen Code verwenden, aber in einer benutzerdefinierten Bindung Handler, aussehen könnte:

ko.bindingHandlers.valueAsCurrency = { 
    init: function(element, valueAccessor) { 
     var observable = valueAccessor(), 
      formatted = ko.computed({ 
       read: function (key) { 
        return '$' + (+observable()).toFixed(2); 
       }, 
       write: function (value) { 
        value = parseFloat(value.replace(/[^\.\d]/g, "")); 
        observable(isNaN(value) ? null : value); // Write to underlying storage 
       }, 
       disposeWhenNodeIsRemoved: element     
      }); 

     //apply the actual value binding with our new computed 
     ko.applyBindingsToNode(element, { value: formatted }); 
    }   
}; 

Also, in der Bindung Handler wir schaffen unsere berechneten und mit dann den value Bindung dagegen.

Nun wäre Ihrer Ansicht nach Modell keine Änderungen benötigen und Sie würden in der Benutzeroberfläche binden wie:

<td><input data-bind="valueAsCurrency: week1Amount" /></td> 
    <td><input data-bind="valueAsCurrency: week2Amount" /></td> 
    <td><input data-bind="valueAsCurrency: week3Amount" /></td> 

Beispiel hier: http://jsfiddle.net/rniemeyer/sD6y4/

+0

Danke, RP. Es funktioniert perfekt. –

+0

Ich habe eine andere Frage, wie Sie dies auf das Summenfeld anwenden, das schreibgeschützt ist. Auch hier ist mein nicht funktionierender Code http://jsfiddle.net/sD6y4/4/. Da ich sum1, sum2, ..., Felder habe. Ist es in diesem Fall möglich, eine wiederverwendbare Funktion zu machen? Danke im Voraus! –

+0

Sie könnten eine 'textAsCurrency'-Bindung hinzufügen, die nur den' read'-Teil ausführt und die 'text'-Bindung anwendet. Könnte aussehen wie: http://jsfiddle.net/rniemeyer/3nrKD/ –