knockout js 'with' binding, hide if array is empty

the-a-train picture the-a-train · Apr 14, 2013 · Viewed 9.4k times · Source

I have a category drop down list which controls a sub category drop down list. I want to hide the sub categories drop down list if the sub category array is empty for the selected category.

Sample code below:

<script>

    self.categories = ko.observableArray([
            {"name": "top 1", "subcategories":[
                                              {"name": "sub 1"},
                                              {"name": "sub 2"}
                                              ]},
            {"name": "top 2", "subcategories":[]}
    ]);

    self.selected_category = ko.observable();
    self.selected_sub_category = ko.obserable();

</script>

<div>
    <select data-bind="options: categories, optionsText: "name", optionsCaption: "Select", value: selected_category"></select>
</div>  
<div data-bind="with:selected_category">
    <select data-bind="options: subcategories, optionsText: "name", optionsCaption: "Select", value: selected_sub_category"></select>
</div>  

Answer

nemesv picture nemesv · Apr 14, 2013

You need to combine the with binding with the if (or the visible) binding where you can specify your condition:

<div data-bind="with: selected_category">
    <!-- ko if: subcategories.length > 0 -->
    <select data-bind="options: subcategories, optionsText: 'name', 
        optionsCaption: 'Select', value: $parent.selected_sub_category"></select>
    <!-- /ko -->
</div> 

Demo JSFiddle.

Note the usage of the $parent in the value: $parent.selected_sub_category, you need that to access "parent" object because the with creates a child context.

If you don't want to render the whole div when the sub collection is empty then you need to move the with and if outside your div because KO not allow to use multiple control-flow bindings on the same element.

So in that case your HTML would look like this:

<!-- ko with:selected_category -->
    <!-- ko if: subcategories.length > 0 -->
        <div class="mydiv">    
            <select data-bind="options: subcategories, optionsText: 'name', 
                    optionsCaption: 'Select', 
                    value: $parent.selected_sub_category">
            </select>    
        </div> 
    <!-- /ko -->
<!-- /ko -->

Demo JSFiddle.