Search code examples
asp.net-mvccheckboxknockout.jsobservablecomputed-observable

Checkbox not updating value knockout js


I'm new at knockout js and feel I may not be understanding something here. I basically have a MVC checkbox, that when checked will update another field which is dependent on other field calculations. I can get the total amount field to update with respect to all of the other fields except for the checkbox, and I'm not sure what I'm doing wrong. I suspect that it's because I'm not passing in a self, but I'm not sure how I would pass that in with the conditional value in the final equation, but I'm not sure why that would be the case at all either. Maybe someone could shed some light on this.

I also noticed that if I made the calculations into variables and returned the final variable, the initial value would show correctly, but then nothing would make the final field update. Is there a reason this is the case or maybe I'm doing something wrong?

Here is the checkbox markup I'm using

<div class="form-group-sm">
    <label for="bookingType">International Property</label>
    <div class="checkbox">
        @Html.EditorFor(model => model.IsInternationalProperty, new { @id = "internationalProperty", @value = true, @data_bind = "checked: internationalProperty" })
        <label style="width: 200px; text-align: left">Select if it is outside the US</label>
    </div>
</div>

And here is my knockoutjs view model

var viewModel = function (data) {
    var self = this;
    self.internationalProperty = ko.observable();
    self.vendorBookingAmount = ko.observable(2.00);
    self.transactionFeesDue = ko.observable(0.00);
    self.transactionFeesWaived = ko.observable(0.00);
    self.iceBookingFees = ko.observable(0.00);
    self.vacationCashRedeemed = ko.observable(0.00);
    self.pointsDiscount = ko.observable(0.00);
    debugger;
    var international = (self.internationalProperty() == true) ? 0.05 : 0;

    self.memberBalance = ko.computed(function () {
        return (Number(self.vendorBookingAmount()) + Number(self.transactionFeesDue()) -
            Number(self.transactionFeesWaived()) + Number(self.iceBookingFees()) -
            Number(self.vacationCashRedeemed()) - Number(self.pointsDiscount())) +

            (Number(self.vendorBookingAmount()) + Number(self.transactionFeesDue()) -
            Number(self.transactionFeesWaived()) + Number(self.iceBookingFees()) -
            Number(self.vacationCashRedeemed()) - Number(self.pointsDiscount()))*international;
    }, self);
};

ko.applyBindings(new viewModel());

Solution

  • You need to put the calculation of international variable inside of the memberBalance. Right now you are calculating it only once, and then memberBalance is using the same international value

        self.memberBalance = ko.computed(function () {
            var international = (self.internationalProperty() == true) ? 0.05 : 0;
            return (Number(self.vendorBookingAmount()) + Number(self.transactionFeesDue()) -
                Number(self.transactionFeesWaived()) + Number(self.iceBookingFees()) -
                Number(self.vacationCashRedeemed()) - Number(self.pointsDiscount())) +
    
                (Number(self.vendorBookingAmount()) + Number(self.transactionFeesDue()) -
                Number(self.transactionFeesWaived()) + Number(self.iceBookingFees()) -
                Number(self.vacationCashRedeemed()) - Number(self.pointsDiscount()))*international;
        }, self);
    

    EDIT: If you view source and look at your generated HTML, you will see that data-bind statement is just not there for the checkbox. The issue is that @Html.EditorFor has different parameters from @Html.CheckBoxFor, @Html.TextBoxFor etc.

    See post: http://cpratt.co/html-editorfor-and-htmlattributes/

    The syntax you need to use is:

    @Html.EditorFor(model => model.IsInternationalProperty, new { htmlAttributes = new { @id = "internationalProperty", @value = true, @data_bind = "checked: internationalProperty" } })
    

    Note the wrapper object with htmlAttributes property.