Cart editor with kendoDropDown
http://knockoutjs.com/examples/cartEditor.html
by rniemeyer
HTML
<script src="http://knockoutjs.com/examples/resources/sampleProductCategories.js"></script>
<script src="http://knockoutjs.com/downloads/knockout-2.1.0.js"></script>
<link rel="stylesheet" href="http://rniemeyer.github.com/knockout-kendo/css/kendo.common.min.css">
<link rel="stylesheet" href="http://rniemeyer.github.com/knockout-kendo/css/kendo.default.min.css">
<script src="http://cdn.kendostatic.com/2012.1.322/js/kendo.all.min.js"></script>
<script src="http://rniemeyer.github.com/knockout-kendo/js/knockout-kendo.min.js"></script>
<div class='liveExample'>
<table width='100%'>
<thead>
<tr>
<th width='25%'>Category</th>
<th width='25%'>Product</th>
<th class='price' width='15%'>Price</th>
<th class='quantity' width='10%'>Quantity</th>
<th class='price' width='15%'>Subtotal</th>
<th width='10%'> </th>
</tr>
</thead>
<tbody data-bind='foreach: lines'>
<tr>
<td>
<input data-bind="kendoDropDownList: { dataTextField: 'name', dataValueField: 'name', data: sampleProductCategories, value: categoryName }" />
</td>
<td data-bind="with: category">
<input data-bind="kendoDropDownList: { dataTextField: 'name', dataValueField: 'name', data: products, value: $parent.productName }" />
</td>
<td class='price' data-bind='with: product'>
<span data-bind='text: formatCurrency(price)'> </span>
</td>
<td class='quantity'>
<input data-bind='visible: product, value: quantity, valueUpdate: "afterkeydown"' />
</td>
<td class='price'>
<span data-bind='visible: product, text: formatCurrency(subtotal())' > </span>
</td>
<td>
<a href='#'...
CSS
body { font-family: arial; font-size: 14px; }
.liveExample { padding: 1em; background-color: #EEEEDD; border: 1px solid #CCC; max-width: 655px; }
.liveExample input { font-family: Arial; }
.liveExample b { font-weight: bold; }
.liveExample p { margin-top: 0.9em; margin-bottom: 0.9em; }
.liveExample select[multiple] { width: 100%; height: 8em; }
.liveExample h2 { margin-top: 0.4em; font-weight: bold; font-size: 1.2em; }
.liveExample th { text-align: left; font-weight: bold; }
.liveExample .price { text-align: right; padding-right: 2em; }
.liveExample .grandTotal { border-top: 1px solid silver; padding-top: 0.5em; font-size: 1.2em; }
.liveExample .grandTotal SPAN { font-weight: bold; }
.liveExample table, .liveExample td, .liveExample th { padding: 0.2em; border-width: 0; margin: 0; vertical-align: top; }
.liveExample td input, .liveExample td select { width: 8em; }
.liveExample td.quantity input { width: 4em; }
.liveExample td select { height: 1.8em; white-space: nowrap; }
li { list-style-type: disc; margin-left: 20px; }
JavaScript
function formatCurrency(value) {
return "$" + value.toFixed(2);
}
var CartLine = function() {
var self = this;
self.categoryName = ko.observable();
self.category = ko.computed(function() {
var selected = self.categoryName();
return ko.utils.arrayFirst(sampleProductCategories, function(category) {
return selected === category.name;
});
});
self.productName = ko.observable();
self.product = ko.computed(function() {
var selected = self.productName(),
products = self.category() ? self.category().products : [];
return ko.utils.arrayFirst(products, function(product) {
return selected === product.name;
});
});
self.quantity = ko.observable(1);
self.subtotal = ko.computed(function() {
return self.product() ? self.product().price * parseInt("0" + self.quantity(), 10) : 0;
});
// Whenever the category changes, reset the product selection
self.category.subscribe(function() {
self.productName(undefined);
});
};
var Cart = function() {
// Stores an array of lines, and from these, can work out the grandTotal
var self = this;
self.lines = ko.observableArray([new CartLine()]); // Put one line in by default
self.grandTotal = ko.computed(function() {
var total = 0;
$.each(self.lines(), function() {
total += this.subtotal()
})
return total;
});
// Operations
self.addLine = function() {
self.lines.push(new CartLine())
};
self.removeLine = function(line) {
self.lines.remove(line)
};
self.save = function() {
var dataToSave = $.map(self.lines(), function(line) {
return line.product() ? {
productName: line.product().name,
quantity: line.quantity()
} : undefined
});
alert("Could now send this to server: " +...