knockout template nested

example of knockout using nested templates

by homer2

HTML

<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.0.js"></script>
<table border="1">
    <tr><td class="right"><label for="edit">Edit</label></td><td class="left"><input id="edit" type="radio" value="editTmpl" data-bind="checked: mode" /></td></tr>
    <tr><td class="right"><label for="readOnly">Read Only</label></td><td class="left"><input id="readOnly" type="radio" value="readOnlyTmpl" data-bind="checked: mode" /></td></tr>
</table>
<div data-bind="foreach: companies"> <span data-bind="text:name"></span> 
    <table data-bind="foreach: orders"
    border="1">
        <thead>
            <tr>
                <th>CompanyId</th>
                <th>OrderId</th>
                <th>LineItemId</th>
                <th>Product</th>
                <th>Quantity</th>
            </tr>
        </thead>
        <tbody data-bind="foreach: lineItems">
            <tr>
                <td data-bind="text: $parents[1].id"></td>
                <td data-bind="text: $parents[0].id"></td>
                <td data-bind="text:id"></td>
                <td data-bind="template: { name: $root.mode(), data: {field: product} }"></td>
                <td data-bind="template: { name: $root.mode(), data: {field: quantity} }"></td>
            </tr>
        </tbody>
    </table>
</div>
<br/>
<div data-bind="foreach: companies"> <span data-bind="text:name"></span> 
    <table data-bind="foreach: orders"
    border="1">
        <thead>
            <tr>
                <th>CompanyId</th>
                <th>OrderId</th>
                <th>LineItemId</th>
                <th>Product</th>
                <th>Quantity</th>
            </tr>
        </thead>
        <tbody data-bind="template: {name: 'lineItemRow', foreach: lineItems}">
        </tbody>        
    </table>    
</div>
<script type="text/html" id="lineItemRowTest">
    <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td></tr>
</script>
<script type="text/html" id="lineItemRow">
    <tr>
                <td...

CSS

input {
    width: 60px;
}

JavaScript

function LineItem(id, orderId, product, quantity) {
    var self = this;
    self.id = id;
    self.orderId = orderId;
    self.product = ko.observable(product);
    self.quantity = ko.observable(quantity);
}

function Order(id, companyId) {
    var self = this;
    self.id = id;
    self.companyId = companyId;
    self.lineItems = ko.observableArray();

    self.addLineItems = function (lineItems) {
        if ($.isArray(lineItems)) {
            ko.utils.arrayPushAll(self.lineItems(), lineItems);
            self.lineItems.valueHasMutated();
        } else {
            self.lineItems.push(lineItems);
        }
    };
    self.removeListItem = function (lineItem) {
        self.lineItems.remove(lineItem);
    };
}

function Company(id, name) {
    var self = this;
    self.id = id;
    self.name = ko.observable(name);
    self.orders = ko.observableArray();

    self.addOrders = function (orders) {
        if ($.isArray(orders)) {
            ko.utils.arrayPushAll(self.orders(), orders);
            self.orders.valueHasMutated();
        } else {
            self.orders.push(orders);
        }
    };
    self.removeOrder = function (order) {
        self.orders.remove(order);
    };
}


function MyViewModel() {
    var self = this;
    self.mode = ko.observable("editTmpl");
    self.companies = ko.observableArray();

    self.addCompanies = function (companies) {
        if ($.isArray(companies)) {
            ko.utils.arrayPushAll(self.companies(), companies);
            self.companies.valueHasMutated();
        } else {
            self.companies.push(companies);
        }
    };
    self.removeCompany = function (company) {
        self.companies.remove(company);
    };
}

var vm = new MyViewModel();
vm.addCompanies(new Company(1, "Firsties"));
vm.companies()[0].addOrders(new Order(1, 1));
vm.companies()[0].orders()[0].addLineItems(new LineItem(1, 1, "milk", 8));
vm.companies()[0].orders()[0].addLineItems(new LineItem(2, 1, "pizza",...