const stringCompare = (a, b) => a.localeCompare(b);
const numericCompare = (a, b) => a > b ? 1 : a < b ? -1 : 0;
const products = ko.observableArray([
{ name: "Bread", cost: 3.10 },
{ name: "Almond Milk", cost: 1.30 },
{ name: "Chocolate", cost: 2.90 }
]);
const sorters = [
{
label: "By cost",
sort: (a, b) => numericCompare(a.cost, b.cost)
},
{
label: "Alphabetically",
sort: (a, b) => stringCompare(a.name, b.name)
}
];
const desc = ko.observable(true);
const sorter = ko.observable(sorters[0]);
const sortMethod = ko.pureComputed(() => desc()
? (a, b) => -1 * sorter().sort(a, b)
: sorter().sort
)
const sortedProducts = ko.pureComputed(() =>
products().sort(sortMethod())
);
const newProduct = {
name: ko.observable(""),
cost: ko.observable(0)
};
const removeProduct = p => {
products.remove(p);
}
const addProduct = () => {
products.push({
name: newProduct.name(),
cost: +newProduct.cost()
});
newProduct.name("");
newProduct.cost(0);
};
ko.applyBindings({ sorters, desc, sortedProducts, newProduct, addProduct, removeProduct })
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div>
Sort by: <select data-bind="options: sorters, value: sorter, optionsText: 'label'"></select>
Descending <input type="checkbox" data-bind="checked: desc">
</div>
<table>
<thead>
<tr>
<th>no.</th>
<th>Name</th>
<th>Cost</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: sortedProducts">
<tr>
<td data-bind="text: $index() + 1"></td>
<td data-bind="text: name"></td>
<td data-bind="text: '$' + cost.toFixed(2)"></td>
<td>
<button data-bind="click: $root.removeProduct">remove</button>
</td>
</tr>
</tbody>
<tbody data-bind="with: newProduct">
<tr>
<td></td>
<td>
<input data-bind="value: name" placeholder="product name">
</td>
<td>
<input type="number" min="0" step="0.1" data-bind="value: cost">
</td>
<td>
<button data-bind="click: addProduct">add</button>
</td>
</tr>
</tbody>
</table>