Search code examples
javascriptjqueryknockout.jsknockout-2.0

Show hide div and apply css rule in KnockoutJS with boolean value


I'm trying to do two dynamic actions with KnockoutJS.

First, I want to apply specific css rule if the value is true, and also I want to toggle visibility of table row again checking the same value, if its true, then display the div.

This is what I have:

<th class="name" data-bind="css: { text_linethrough: !$root.HasDiscount() }, text: '$' + (Price)"></th>

<tr data-bind="visible: $root.HasDiscount(), css: { package5_Discount_Background: Name == 'Cady Kids Package 5' }">
                                        <th class="name" style="width: 60% !important;"><span></span>&nbsp;
                                        </th>
                                        <th class="name">
                                            PRE-ORDER PRICE:&nbsp;
                                        </th>
                                        <th class="name" data-bind="text: '$' + (Price - 10)"></th>
                                    </tr>

So, if the $root.HasDiscount() returns true, then I'm expecting that both the css will be applied, and the table row will be visible.

Although, the value is true, I'm still not getting the correct css rule and the row is still not visible.

This is how HasDiscount value is created:

t.HasDiscount = ko.computed(function() {
                $.ajax({
                    type: "POST",
                    url: "/webservices/Shopping.asmx/checkShowDiscountedPrice",
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    success: function (i) {
                        if (i.d) {
                            return i.d;
                        } else {
                            return false;
                        }
                    },
                    error: function (n) {
                        u(n);
                    }
                });

                return false;
            });

Solution

  • You should not be making an ajax call inside the computed like that. It is an asynchronous call which means the function returns before the call to the server has made the round trip causing the return false that fires at the end to always fire.

    You could try

    t.HasDiscount = ko.computed(function() {
                    $.ajax({
                        type: "POST",
                        url: "/webservices/Shopping.asmx/checkShowDiscountedPrice",
                        contentType: "application/json; charset=utf-8",
                        dataType: "json",
                        async: false,
                        success: function (i) {
                            if (i.d) {
                                return i.d;
                            } else {
                                return false;
                            }
                        },
                        error: function (n) {
                            u(n);
                        }
                    });
    
                    return false;
                });
    

    but I doubt that is a best practice

    I would call make the ajax call separately and when it returns update an observable value. Then return that observable property in the computed.

    function someOtherFunction(){
     $.ajax({
                        type: "POST",
                        url: "/webservices/Shopping.asmx/checkShowDiscountedPrice",
                        contentType: "application/json; charset=utf-8",
                        dataType: "json",
                        success: function (i) {
                            if (i.d) {
                                t.HasDiscount (i.d);
                            } else {
                                t.HasDiscount (false);
                            }
                        },
                        error: function (n) {
                            u(n);
                        }
                    });
    }
    
    t.HasDiscount = ko.observable(false);