Knockout.js textInput fields dependent on each other

0 votes
asked Dec 15, 2015 by user2672932

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?

1 Answer

+4 votes
answered Dec 15, 2015 by sam-c

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/

Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...