2021年3月25日星期四

Knockout JS writable computed value doesn't fire another computed value when writing function is used

I use Knockout Js for a few months. But I stuck on a problem. I have 2 view models. One is the whole bill view model who has the subtotal of the bill and the taxes with the grand total. A part of the main view model of the bill is:

    function BillViewModel() {           var self = this;           self.timesheets = ko.observableArray([]);           self.items = ko.observableArray([]);           self.amountdummy = ko.observable();           self.subtotal = ko.computed(function(){               self.amountdummy();               var total = 0;               for(var i = 0; i < this.timesheets().length; i++)               {                   var totalLine = this.timesheets()[i].amount();                   total += parseFloat((totalLine != '' && totalLine !== null && !isNaN(totalLine) ? totalLine: 0));                 for(var i = 0; i < this.items().length; i++)               {                   var totalLine = this.items()[i].amount();                   total += parseFloat((totalLine != '' && totalLine !== null && !isNaN(totalLine) ? totalLine : 0));                             }               return total;           }, self);        };  

Each line of the bill is represented by 2 others view models who are:

    function BillItemViewModel(item) {           var self = this;           self.parent = item.parent;           self.quantity = ko.observable(item.quantity);           self.price = ko.observable(item.price);           self.amount = ko.computed({               read: function(){                   var quantity = getNumberFromFormattedValue(self.quantity());                   if (quantity !== null) { quantity = parseFloat(quantity); }                   var price = getNumberFromFormattedValue(self.price());                   if (price !== null) { price = parseFloat(price); }                   if (!(isNaN(quantity) || isNaN(price) || quantity === null || price === null || quantity === '' || price === '')) {                       var newValue = quantity * price;                       return newValue;                   }                   // Don't change the value               },               write: function(value){                   var newValue = getNumberFromFormattedValue(value);                   if (newValue !== null) { newValue = parseFloat(newValue); }                   var quantity = getNumberFromFormattedValue(self.quantity());                   if (quantity !== null) { parseFloat(quantity); }                   if (!(isNaN(newValue) || isNaN(quantity) || newValue === null || quantity === null || newValue === '' || quantity === '')) {                       self.price( newValue / quantity );                   }                   self.parent.amountdummy.notifySubscribers();               },               owner: self           });           self.quantity.subscribe(function(){              if (self.price() === '' || self.price() === null) {                  self.amount(0);              }            });           self.amount(item.amount);        };  

The 2nd view model is pretty like this one. Except that it is used to enter time and rate and calculate an amount who is added to the subtotal.

The HTML code is:

       <table class="table item" data-bind="visible: items().length > 0">              <tbody data-bind="foreach: items">                   <tr>                         <td class="qty"><input type="text" data-bind="value: quantity, name: function(data, event) { return 'qty_'+ $index(); }()"></td>                         <td class="price"><input type="text" data-bind="value: price, name: function(data, event) { return 'price_'+ $index(); }()"></td>                         <td class="amount"><input type="text" data-bind="value: amount, name: function(data, event) { return 'amount_'+ $index(); }()"></td>                   </tr>             </tbody>         </table>                   <div>             <label for="subtotal">Subtotal</label>             <input id="subtotal" data-bind="value: subtotal" type="text" name="subtotal" readonly>         </div>  

The behaviour of the page is that when user enters quantity and price, the amount of the line is automatically calculated. But if the user can not enter a quantity and a price, he can enter directly the amount.

see JsFiddle for complete example

Everything works fine. But when the user just enter an amount on the line, the subtotal is not updated.

Edit:

I removed everything about taxes. I followed the hint given by Josh by this link . But it is doesn't work again.

See this JsFiddle

Any help will be appreciated

https://stackoverflow.com/questions/66731983/knockout-js-writable-computed-value-doesnt-fire-another-computed-value-when-wri March 21, 2021 at 07:55PM

没有评论:

发表评论