0
votes

So heres a great way to waste 20 minutes. When binding like this in a foreach loop using knockout.js everything works just fine.

    <tbody data-bind="foreach: LineItems">
<tr>
    <td>
        <input data-bind="value: Quantity" class="may-frm-grid-input may-frm-grid-input-txt-num" />
    </td>
    <td><input data-bind="value: UnitPriceExTax" class="may-frm-grid-input may-frm-grid-input-txt-num" /></td>
    <td data-bind="text: LineTotalExTax" class="may-frm-grid-val-lbl"></td>
    <td>
        <input data-bind="value: UnitPriceTaxRate" class="may-frm-grid-input may-frm-grid-input-txt-num" />
    </td>
    <td data-bind="text: LineTotalTaxAmt" class="may-frm-grid-val-lbl"></td>
    <td data-bind="text: LineTotalIncTax" class="may-frm-grid-val-lbl"></td>
</tr>
</tbody>

Note that the bindings are just using the method name not a method call ie. LineTotalExTax not LineTotalExTax()

But outside of a foreach as below:

<tbody>
    <tr>
        <td class="may-frm-grid-lbl-right"></td>
        <td class="may-frm-grid-lbl-right"></td>
        <td class="may-frm-grid-lbl-right"></td>
        <td>
            <input data-bind="value: FreightExTax" class="may-frm-grid-input may-frm-grid-input-txt-num" />
        </td>
        <td>
            <input data-bind="value: FreightTaxRate" class="may-frm-grid-input may-frm-grid-input-txt-num" />
        </td>
        <td data-bind="text: FreightTaxAmt" class="may-frm-grid-val-lbl"></td>
        <td data-bind="text: FreightIncTax" class="may-frm-grid-val-lbl"></td>
    </tr>
</tbody>

This seems to create problems. So although the values get bound when binding to computed observables like this:

function EoiViewModel() {
            var self = this;
            self.LineItems = ko.observableArray([]);
            self.QuoteID = ko.observableArray();
            self.CurrencyID = ko.observableArray();

            self.FreightExTax = ko.observable(0);
            self.FreightTaxRate = ko.observable(0);

            self.FreightTaxAmt = ko.computed(function () {
                return (self.FreightExTax() * (1 + (self.FreightTaxRate() / 100))) - self.FreightExTax();
            });
            self.FreightIncTax = ko.computed(function () {
                return  self.FreightExTax() + self.FreightTaxAmt();
            });
            self.TotalExTax = ko.observable(0);
            self.TotalTaxes = ko.observable(0);
            self.TotalIncTax = ko.observable(0);

        }

The value returned for:

  <td data-bind="text: FreightIncTax" class="may-frm-grid-val-lbl"></td>

would be an insanely annoying 100.11110000 for a freightextax of 10 and a freighttaxrate of 1. i.e. it was using "+" as a concantenation operator not an additive operator.

So my question is why? How did I "get away" with no method call syntax in the foreach but not in the bind outside of a loop?

Update:

And i should also add the foreach loop fail to bind is I add in method "()" syntax so clearly its something to do with scope but what?

1

1 Answers

2
votes

I don't think this has anything to do with the ()s. In Knockout, binding to a single observable or computed can be done with or without ()s. This is because Knockout basically runs ko.unwrap() on the binding to get its value.

You're getting the a concatenation problem here because although the observables FreightExTax and FreightTaxRate were originally assigned numbers, they became strings because they were bounded to an input box. As soon as the values were modified, they were now strings. And this line:

return self.FreightExTax() + self.FreightTaxAmt();

became a concatenation. A parseFloat() fixes it...

return parseFloat(self.FreightExTax()) + self.FreightTaxAmt();

Fiddle... http://jsfiddle.net/VSZE4/