Spinner Binding

Supports disable attribute and is intended for use with a feature detection library such as Modernizr.

HTML

<link rel="stylesheet" href="http://code.jquery.com/ui/1.9.0/themes/base/jquery-ui.css">
<script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.9.0/jquery-ui.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.min.js"></script>
<script src="urlObj = {         protoco"></script>
<script src=" //&lt;![CDATA[ // Copyright (c) Microsoft Corporation.  All rights reserved. function InputUtil(errTextElementID, errDisplayElementID) {      if (!errTextElementID)  errTextElementID = &#39;errorText&#39;;      if (!errDisplayElementID)  errDisplayElementID = &#39;erro"></script>
<p>Test in IE8 to see jQuery UI spinner.</p>
<table>
    <tbody data-bind="foreach: orders">
        <tr>
            <td data-bind="text: Name"></td>
            <td><input type="number" style="width: 100px;" data-bind="spinner: Price, valueUpdate: 'afterkeydown'" /></td>
          <td data-bind="text: Price"></td>
            <td><input type="number" style="width: 50px;" data-bind="spinner: VAT, disable: Price() < 100" /></td>
            <td><input type="number" style="width: 50px;" data-bind="spinner: Number" /></td>
            <td data-bind="text: Final"></td>
            <td><a href="#" data-bind="click: $parent.removeOrder">Remove</a></td>
        </tr>    
    </tbody>
</table>


<button data-bind="click: save">Save</button>

CSS

table th, table td {
  padding: 3px;
}

JavaScript

ko.bindingHandlers.spinner = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        if (Modernizr.inputtypes.number) {
            ko.bindingHandlers.value.init.apply(null, arguments);
        } else {
            //initialize spinner with some optional options
            var options = allBindingsAccessor().spinnerOptions || {};
            $(element).spinner(options);
            
            //handle the field changing
            $(element).on("spinstop", function () {
                var observable = valueAccessor();
                observable($(element).spinner("value"));
            });
            
            //handle disposal
            ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
                $(element).off("spinstop");
                $(element).spinner("destroy");
            });
        }
        
    },
    update: function (element, valueAccessor, allBindingsAccessor) {
        if (Modernizr.inputtypes.number) {
            ko.bindingHandlers.value.update.apply(null, arguments);
        } else {
            var value = ko.utils.unwrapObservable(valueAccessor());
            
            var disable = allBindingsAccessor().disable;
            
            if (typeof disable !== "undefined") {
                $(element).spinner((disable) ? "disable" : "enable");
            }
            
            var current = $(element).spinner("value");
            if (value !== current) {
                $(element).spinner("value", value);
            }
        }
    }
};

function Order(name, price, vat, number) {
    var self = this;

    self.Name = ko.observable(name);
    self.Price = ko.observable(price);
    self.VAT = ko.observable(vat);
    self.Number = ko.observable(number);

    self.Final = ko.computed(function() {
        return (self.Price() + self.VAT()) * self.Number();
    });
}

function ViewModel() {
    var self = this;

    self.orders = ko.observableArray();

    self.removeOrder =...