jQuery TimePicker with Knockout

by Jon Kittell

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.0/knockout-min.js"></script>
<script src="http://wvega.github.io/timepicker/resources/jquery-timepicker/jquery.timepicker.min.js"></script>
<link rel="stylesheet" href="http://wvega.github.io/timepicker/resources/jquery-timepicker/jquery.timepicker.min.css">
<h1>jQuery TimePicker with Knockout.js</h1>

<p>All Date objects returned by the timepicker have the date part set to Aug 24, 1988. That date is not important, but using the same value every time makes internal calculations easier.</p>
<p>Current value is <span data-bind="text: time"></span></p>

<form>
  <input type="text" name="timepicker" data-bind="timepicker: time, timepickerOptions: { timeFormat: 'HH:mm:ss p' }" />
</form>

<a href="http://github.com/wvega/timepicker"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" /></a>
  
  <p>Based on code sent by Jason Moguera and the answers in <a href="http://stackoverflow.com/questions/6612705/knockout-with-jquery-ui-datepicker">http://stackoverflow.com/questions/6612705/knockout-with-jquery-ui-datepicker</a></p>

CSS

body {
    background: #EFEFEF;
    padding: 20px;
}
h1 {
    font-weight: bold;
    margin-top: 100px;
}
p {
    margin: 10px 0;
}
p span {
  font-weight: bold;
  font-size: 0.9em;
}

JavaScript

(function($, undefined) {
    ko.bindingHandlers.timepicker = {
        init: function (element, valueAccessor, allBindingsAccessor) {
            //initialize timepicker with some optional options
            var options = allBindingsAccessor().timepickerOptions || {},
                input = $(element).timepicker(options);

            //handle the field changing
            ko.utils.registerEventHandler(element, "time-change", function (event, time) {
                var observable = valueAccessor(),
                    current = ko.utils.unwrapObservable(observable);
                
                if (current - time !== 0) {
                    observable(time);
                }
            });

            //handle disposal (if KO removes by the template binding)
            ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
                $(element).timepicker("destroy");
            });
        },

        update: function (element, valueAccessor) {
            var value = ko.utils.unwrapObservable(valueAccessor()),
                // calling timepicker() on an element already initialized will
                // return a TimePicker object
                instance = $(element).timepicker();
 
            if (value - instance.getTime() !== 0) {
                instance.setTime(value);
            }
        }
    };

    var model = {
        // all Date objects returned by the timepicker have the date
        // part set to Dec 31 1899. That date is not important, but
        // using the same value every time makes internal calculations
        // easier.
        time: ko.observable($.fn.timepicker.parseTime('2:20:35 pm'))
    }

    $(function() {
        ko.applyBindings(model);
    });
})(jQuery);