Adding category lines based on properties of the corresponding item

I have a sorted, static list to display with KO, and you want to show category headers whenever the category has changed (since the list is sorted by categories). I'm still on KO, is this the way β€œKO” does this, or is there a better approach? In particular, the syntax for accessing the previous item in the list is a little hairy, which makes me suspect that I am missing a function that will improve this. :-)

Live Copy | Source

HTML:

<table>
  <tbody data-bind="foreach: items">
    <!-- ko if: $index() === 0 || $parent.items()[$index() - 1].category() !== category() -->
    <tr class="category">
      <td colspan="2" data-bind="text: category"></td>
    </tr>
    <!-- /ko -->
    <tr>
      <td data-bind="text: item"></td>
      <td class="num" data-bind="text: quantity"></td>
    </tr>
  </tbody>
</table>

JavaScript: (Obviously this is just a quick and dirty virtual machine for example)

function Item(category, item, quantity) {
    this.category = ko.observable(category);
    this.item = ko.observable(item);
    this.quantity = ko.observable(quantity);
}

var vm = {
    items: ko.observableArray([
        new Item("Fruit", "Apples", 27),
        new Item("Fruit", "Oranges", 17),
        new Item("Fruit", "Kiwis", 3),
        new Item("Vegetables", "Celery", 16),
        new Item("Vegetables", "Carrots", 72),
        new Item("Sundries", "Toothpaste", 10),
        new Item("Sundries", "Washing-up liquid", 8)
    ])
};
ko.applyBindings(vm, document.body);

Result: (there are some trivial CSS that are not relevant)

Table with category rows

+4
2

, , :

JS:

function Item(category, itemList) {
    this.category = ko.observable(category);
    this.itemList = ko.observableArray(itemList);

}

var vm = {
    items: ko.observableArray([
        new Item("Fruit", [{"item": "Apples", "qty": 27 }, 
                           {"item": "Oranges", "qty": 17}, 
                           {"item": "Kiwis", "qty": 3}]),              
        new Item("Vegetables", [{"item": "Celery", "qty": 16},
                                {"item": "Carrots", "qty": 72}]),      
        new Item("Sundries", [{"item": "Toothpaste", "qty": 10},
                              {"item": "Washing-up liquid", "qty": 8}]),    
    ])
};

ko.applyBindings(vm, document.body);

HTML:

<table>
  <tbody data-bind="foreach: items">    
    <tr class="category">
      <td colspan="2" data-bind="text: category"></td>
    </tr>
    <!-- ko foreach: itemList -->
        <tr>
          <td data-bind="text: item"></td>
          <td class="num" data-bind="text: qty"></td>
        </tr>
    <!-- /ko -->    
  </tbody>
</table>

. JSFiddle : http://jsfiddle.net/y4yPv/2/

+4

categoryId . :

HTML:

<table>
    <tbody data-bind="foreach: items">
        <!-- ko if: type == 0 -->
        <tr class="category">
            <td colspan="2" data-bind="text: item"></td>
        </tr>
        <!-- /ko -->
        <!-- ko if: type == 1 -->
        <tr>
            <td data-bind="text: item"></td>
            <td class="num" data-bind="text: quantity"></td>
        </tr>
        <!-- /ko -->
    </tbody>
</table>

ViewModel:

function Item(type, categoryId, item, quantity) {
    this.type = type;
    this.categoryId = categoryId;
    this.item = ko.observable(item);
    this.quantity = ko.observable(quantity);
}

var vm = {
    items: ko.observableArray([
        new Item(0, 1, "Fruit"), 
        new Item(1, 1, "Apples", 27),
        new Item(1, 1, "Oranges", 17),
        new Item(1, 1, "Kiwis", 3),
        new Item(0, 2, "Vegetables"),
        new Item(1, 2, "Celery", 16),
        new Item(1, 2, "Carrots", 72),
        new Item(0, 3, "Sundries"),
        new Item(1, 3, "Toothpaste", 10),
        new Item(1, 4, "Washing-up liquid", 8)
    ])
};
ko.applyBindings(vm, document.body);
+2

All Articles