简体   繁体   中英

Knockout.js textInput fields dependent on each other

So the user wants to buy some potato. He can either enter the amount of potato in kilograms and get total price in dollars, or he can do the reverse - enter dollars and get kilograms of potato. So there's 2 input fields.

Requirements: values must update immediately after typing. Entering value in one field updates the other, and vice versa. Kilograms must stay whole, with one exception - when user enters not whole weight himself.

Price is stored internally in cents. Price is shown to the user as dollars per 1000 kilogram. Amount in kilograms is always integer.

Here is my code:

var ViewModel = function () {
    var self = this;

    this.totalPrice = ko.observable();
    this.pricePerKg = ko.observable(999);
    this.potatoWeight = ko.computed({
        read: function () {
            var totalPrice = self.totalPrice();
            var potatoWeight = (totalPrice * 100) / self.pricePerKg() * 1000;
            return Math.round(potatoWeight);
        },
        write: function (potatoWeight) {
            var totalPrice = (potatoWeight * self.pricePerKg()) / 100 / 1000;
            self.totalPrice(totalPrice.toFixed(2));

        }
    });

};
ko.applyBindings(new ViewModel());

HTML:

<label for="potato">Potato, kg</label>
<input type="text" id="potato" data-bind="textInput: potatoWeight">
<label for="priceTotal">Price total, $</label>
<input type="text" id="priceTotal" data-bind="textInput: totalPrice">

<div> Price per 1000 kilogram:
<span data-bind="text: (pricePerKg() / 100).toFixed(2)">
</span>$

Jsfiddle: https://jsfiddle.net/9td7seyv/13/

Problem : when you type value in "potato weight" it updates not only value in dollars, but also itself. Because of rounding it leads to inconsistencies. Go to jsfiddle above and try to type 500 in weight field. It turns itself to 501 the moment you enter the last zero.

So is there a way to stop the field updating itself, or probably some other approach to this problem is needed?

For this case, the most straight forward way I can think of is to keep a copy of the value entered by the user after any calculation ... like in the code below.

var ViewModel = function () {
    var self = this;

    this.totalPrice = ko.observable();
    this.pricePerKg = ko.observable(999);
    this.weight=ko.observable();
    this.potatoWeight = ko.computed({
        read: function () {
            return self.weight();
        },
        write: function (potatoWeight) {
            var totalPrice = (potatoWeight * self.pricePerKg()) / 100 / 1000;
            self.totalPrice(totalPrice.toFixed(2));
                        self.weight(potatoWeight);
        }
    });

};
ko.applyBindings(new ViewModel());

https://jsfiddle.net/9td7seyv/16/

update : For both values https://jsfiddle.net/9td7seyv/19/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM