Data binding nested JSON with Knockoutjs
http://stackoverflow.com/questions/9088423/data-binding-nested-json-with-knockoutjs
by Doug Hill
HTML
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<div>
<!-- ko foreach:lines -->
<!-- ko foreach:$parent.menus -->
<select data-bind='options: categories, optionsText: "name", value: $parent.category' ></select>
<!-- /ko -->
<!-- ko with: category -->
<select data-bind='options: products, optionsText: "name", value: $parent.product'></select>
<!-- /ko -->
<!-- ko with: product -->
<span data-bind="text: price"></span>
<select data-bind='options: options, optionsText: "name"'></select>
<input data-bind="value: $parent.quantity, valueUpdate: 'keyup'" />
<!-- /ko -->
<span data-bind="text: subtotal"></span>
<a href='#' data-bind='click: $parent.removeLine'>Remove</a><br/>
<!-- /ko -->
</div>
Total value: <span data-bind='text: grandTotal()'> </span>
<button data-bind="click: addLine">Add Product</button>
JavaScript
$(function() {
function formatCurrency(value) {
return "$" + value.toFixed(2);
}
//single Option with an Observable amount
function Option(name, quantity) {
var self = this;
self.name = name;
self.quantity = ko.observable(quantity);
}
//single Product containing an Observable Array of Options (that contain Observable data)
function Product(name, price, quantity, options) {
var self = this;
self.name = ko.observable(name);
self.price = price;
self.quantity = ko.observable(quantity);
self.options = ko.observableArray(ko.utils.arrayMap(options, function(option) {
return new Option(option.name, option.quantity);
}));
self.addOption = function(name, quantity) {
self.options.push(new Option(name, quantity));
};
}
//single Category containing an Observable Array of Products (that contain Observable Arrays with Observable data)
function Category(name, products) {
var self = this;
self.name = name;
self.products = ko.observableArray(ko.utils.arrayMap(products, function(product) {
return new Product(product.name, product.price, product.quantity, product.options);
}));
}
//single Menu containing an Observable Array of Categories (that contain Observable Arrays with Observable data)
function Menu(categories) {
var self = this;
self.categories = ko.observableArray(ko.utils.arrayMap(categories, function(category) {
return new Category(category.name, category.products);
}));
self.addCategory = function(name) {
self.categories.push(new Category(name));
};
}
function CartLine() {
var self = this;
self.category = ko.observable();
self.product = ko.observable();
self.quantity = ko.observable(1);
self.subtotal = ko.computed(function() {
...