2013-04-10 10 views
8

siehe Arbeits jsFiddle: http://jsfiddle.net/ruslans/vFK82/Kreis Abhängigkeit von Knockout berechnet

Ich habe 3 Felder: Nettopreis (Bsp. Steuern), Steuerbetrag und Gesamtpreis (Preis ohne MwSt + Steuerbetrag.). der NetPrice und der Total sind schreibbar, d. H. Sie können beide ändern und die anderen 2 Werte müssen automatisch berechnet werden.

Die Art, wie ich es getan habe, verwendet 3 beobachtbare und 2 berechnete Knockout-Objekte, aber ich dachte, dass jemand, der Knockout viel besser kennt, einen effizienteren Weg vorschlagen könnte.

html:

Net Price: 
<input type="textbox" data-bind="value: NetPriceCalc" /> 
<br />Tax Amount: 
<label data-bind="html: TaxAmt"></label> 
<br />Total: 
<input type="textbox" data-bind="value: TotalCalc" /> 

Skript:

var viewModel = { 
    NetPrice: ko.observable(100), 
    TaxAmt: ko.observable(20), 
    Total: ko.observable(120), 
    TaxRate: 0.2 
}; 

viewModel.updateTaxAmt = function (useNetPrice) { 
    if (useNetPrice) { 
     return this.TaxAmt(this.NetPrice() * this.TaxRate); 
    } else { 
     var total = Number(this.Total()); 
     var taxAmt = total - total/(1 + this.TaxRate); 
     return this.TaxAmt(taxAmt); 
    } 
}; 
viewModel.updateNetPrice = function() { 
    this.NetPrice(Number(this.Total()) - Number(this.TaxAmt())); 
}; 
viewModel.updateTotal = function() { 
    this.Total(Number(this.NetPrice()) + Number(this.TaxAmt())); 
}; 

viewModel.NetPriceCalc = ko.computed({ 
    read: function() { 
     console.log("NetPriceCalc read"); 
     return viewModel.NetPrice(); 
    }, 
    write: function (value) { 
     console.log("NetPriceCalc write"); 
     viewModel.NetPrice(value); 
     viewModel.updateTaxAmt(true); 
     return viewModel.updateTotal(); 
    } 
}); 
viewModel.TotalCalc = ko.computed({ 
    read: function() { 
     console.log("TotalCalc read"); 
     return viewModel.Total(); 
    }, 
    write: function (value) { 
     console.log("TotalCalc write"); 
     viewModel.Total(value); 
     viewModel.updateTaxAmt(false); 
     return viewModel.updateNetPrice(); 
    } 
}); 

ko.applyBindings(viewModel); 

Antwort

4

Eine etwas bessere und effiziente Art und Weise könnte dies sein:

Working Fiddle

Html

Net Price: 
<input type="textbox" data-bind="value: NetPrice" /> 
<br />Tax Amount: 
<label data-bind="html: TaxAmt"></label> 
<br />Total: 
<input type="textbox" data-bind="value: Total" /> 

JS

function viewModel() { 
    var self = this; 

    self.NetPrice = ko.observable(100); 

    self.TaxRate = 0.2; 

    self.TaxAmt = ko.computed(function() { 
     return parseFloat(self.NetPrice()) * self.TaxRate; 
    }); 

    self.Total = ko.computed({ 
     read: function() { 
       return parseFloat(self.NetPrice()) + self.TaxAmt(); 
     }, 
     write: function(val){ 
       var total = parseFloat(val); 
       var taxAmt = total - total/(1 + self.TaxRate);  
       self.NetPrice(total - taxAmt); 
     } 
    }); 
} 

Hoffe, es hilft!

+0

ausgezeichnet! danke – Tsar

+0

Ziemlich cool. Sie können dem Datenbindungsattribut der Felder "valueUpdate: 'afterkeydown'" hinzufügen, sodass sie bei jedem Schlüsselstrich aktualisiert werden. –

5

Einige Kommentare zum OP:

  • Sie brauchen die nicht return Klausel in der write Methode des ko.computed.
  • Ihr Ansatz verwendet die Funktion Number() an mehreren Stellen und Sie möchten dies möglicherweise ändern, um eine bestimmte Genauigkeit (oder einen zentralen Ort für die Validierung von Benutzereingaben) zu erhalten. So können Sie ko.extenders verwenden, um das zu verbessern. Und ich würde ausdrücklich den Extender empfehlen, der bereits vom Ko-Team ko.extenders.numeric gemacht wurde.
  • Ihr Ansatz verwendet auch console.log() an mehreren Stellen, und Sie möchten vielleicht einen anderen ko.extender des KO-Teams ko.extenders.logChange verwenden.
  • Statt einer ko.computed in diesem Fall denke ich, es ist besser zu verwenden subscribe, da es weniger Code (und wahrscheinlich unbedeutend schneller) braucht.

Mein Ansatz wäre dies:

function viewModel() { 
    this.TaxRate = 0.2; 
    this.NetPrice = ko.observable().extend({ numeric: 2, logChange: "NetPrice" }); 
    this.TaxAmt = ko.observable().extend({ numeric: 2, logChange: "TaxAmt" }); 
    this.Total = ko.observable().extend({ numeric: 2, logChange: "Total" }); 

    this.NetPrice.subscribe(function (newNetPrice) { 
     this.TaxAmt(newNetPrice * this.TaxRate); 
     this.Total(newNetPrice + this.TaxAmt()); 
    }, this); 
    this.Total.subscribe(function (newTotal) { 
     this.TaxAmt(newTotal - newTotal/(1 + this.TaxRate)); 
     this.NetPrice(newTotal - this.TaxAmt()); 
    }, this); 

    this.NetPrice(100); 
} 

// then I have the extenders code copied exactly as seen in: http://knockoutjs.com/documentation/extenders.html) 
ko.extenders.numeric = ... 
ko.extenders.logChange = ... 

// and finally init everything as usual 
ko.applyBindings(new viewModel()); 

Sie können die Arbeits Geige siehe hier: http://jsfiddle.net/protron/JFPgu/2/

Hinweis, wie die Zahlen in dieser Lösung nicht mehr Dezimalstellen als die angegebene auf die haben numerische Extender (sogar der vom Benutzer eingegebene Wert wird automatisch auf die gewünschte Genauigkeit festgelegt).

Und meine Antwort mit der derzeit akzeptierten Antwort von Gaurav vergleichen (was auch ziemlich nett und einfach ist): Ich denke, der Hauptvorteil meiner Vorgehensweise ist, dass Sie diese fantastischen Extender verwenden können.

+0

Ooh, 'Extender' sind ziemlich cool, besonders die Tatsache, dass ich Subobservables zu bestehenden Observablen hinzufügen kann - mein Anwendungsfall sind Fehlermeldungen über bestimmte Teile der gerenderten UI, die von einem anderen Endpunkt kommen (nicht meine Wahl der API-Architektur)). –

0

Kann nicht versprechen, dass dies das Problem beheben wird, aber manchmal kann das Aktivieren von verzögerten Updates Probleme wie diese beheben.

Es ist ein gutes Feature zu beachten, aber seien Sie vorsichtig, es für eine bereits funktionierende Anwendung zu aktivieren - und auch wenn Sie ein zugrunde liegendes Problem haben, dann werden Sie immer noch das beheben wollen.

http://knockoutjs.com/documentation/deferred-updates.html

+0

Hinweis: Dies ist NICHT das gleiche wie eine verzögerte beobachtbare - und ist ein neues Feature von 3.4.0 –

Verwandte Themen