Utility functions in KnockoutJS
http://www.knockmeout.net/2011/04/utility-functions-in-knockoutjs.html
by sas_sam
HTML
<script src="http://knockoutjs.com/downloads/knockout-2.2.1.debug.js"></script>
<h3>1- JSON string from server</h3>
<p data-bind="text: JSONdataFromServer"></p>
<h3>2- Converted to an object with ko.parseJson</h3>
<p data-bind="text: ko.toJSON(dataFromServer)"></p>
<h3>3- Mapped to use observables and add a dependentObservable</h3>
<p data-bind="text: ko.toJSON(mappedData)"></p>
<hr />
<h3>4- Display in an editor</h3>
<table id="mytable">
<thead>
<tr>
<th>Name</th>
<th>Category</th>
<th>Price</th>
<th>w/Tax</th>
<th></th>
</tr>
</thead>
<tbody data-bind="template: { name: 'itemsTmpl', foreach: filteredItems }"></tbody>
<script id="itemsTmpl" type="text/html">
<tr data-bind="css: { matched: $data === $root.firstMatch() }">
<td>
<input data-bind="value: name" />
</td>
<td>
<select data-bind="options: $root.categories, value: category"></select>
</td>
<td>
<input class="n" data-bind="value: price" />
</td>
<td class="n" data-bind="text: priceWithTax">
</td>
<td>
<a href="#" data-bind="click: $root.removeItem.bind($root)">Delete</a>
</td>
</tr>
</script>
<tr>
<td>
<a href="#" data-bind="click: addItem">Add Item</a>
</td>
<td></td>
<td class="n">Total: </td>
<td class="n" data-bind="text: total"></td>
<td></td>
</tr>
</table>
<h3>5- Filter display by name</h3>
<p>Filter: <input data-bind="value: filter, valueUpdate: 'afterkeydown'" /></p>
<h3>6- Find first match by name</h3>
<p>Search: <input data-bind="value: search, valueUpdate: 'afterkeydown'" /></p>
<hr />
<h3>7- Use ko.utils.arrayMap to build an array with just categories used</h3>
<p data-bind="text: ko.toJSON(justCategories)"></p>
<h3>8- Use...
CSS
body, a, p { font-size: .85em; }
input { width: 100px; }
table { border: 1px solid black; }
h3, p, td, th { padding: 3px; }
h3 { font-weight: bold; }
.matched { background-color: yellow; }
.n { text-align: right; }
JavaScript
function Item(name, category, price) {
this.name = ko.observable(name);
this.category = ko.observable(category);
this.price = ko.observable(price);
this.priceWithTax = ko.dependentObservable(function() {
return (this.price() * 1.05).toFixed(2);
}, this);
}
var viewModel = {
categories: ["Bread", "Dairy", "Fruits", "Vegetables"],
items: ko.observableArray([]),
filter: ko.observable(""),
search: ko.observable(""),
addItem: function() {
this.items.push(new Item("New", "", 1));
},
removeItem: function(item) {
this.items.remove(item);
}
};
//ko.utils.arrayFilter - filter the items using the filter text
viewModel.filteredItems = ko.dependentObservable(function() {
var filter = this.filter().toLowerCase();
if (!filter) {
return this.items();
} else {
return ko.utils.arrayFilter(this.items(), function(item) {
return ko.utils.stringStartsWith(item.name().toLowerCase(), filter);
});
}
}, viewModel);
//ko.utils.arrayForEach - return a total by adding all prices
viewModel.total = ko.dependentObservable(function() {
var total = 0;
ko.utils.arrayForEach(this.filteredItems(), function(item) {
var value = parseFloat(item.priceWithTax());
if (!isNaN(value)) {
total += value;
}
});
return total.toFixed(2);
}, viewModel);
//ko.utils.arrayFirst - identify the first matching item by name
viewModel.firstMatch = ko.dependentObservable(function() {
var search = this.search().toLowerCase();
if (!search) {
return null;
} else {
return ko.utils.arrayFirst(this.filteredItems(), function(item) {
return ko.utils.stringStartsWith(item.name().toLowerCase(), search);
});
}
}, viewModel);
//ko.utils.arrayMap - get a list of used categories
viewModel.justCategories = ko.dependentObservable(function() {
var categories = ko.utils.arrayMap(this.items(),...