Using Knockout.js how do bind a Date property to a HTML5 date picker?

While @amakhrov answer will work (and would be even better if used writeable computed observable like sujested by @Stijn) I decided to do this using Custom Bindings.

The main advantage of doing this is reusability - I just have to use data-bind="datePicker : MyDate" whereever I want to tie this in. I can also modify other properties of the input element so this could be really useful if binding to complex jQuery (and other) controls.

(Read here for more pro/cons about the 3 choices to do this sort of thing)

HTML

<input data-bind="datePicker : MyDate" type="date">

JS

ko.bindingHandlers.datePicker = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {                    
        // Register change callbacks to update the model
        // if the control changes.       
        ko.utils.registerEventHandler(element, "change", function () {            
            var value = valueAccessor();
            value(new Date(element.value));            
        });
    },
    // Update the control whenever the view model changes
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value =  valueAccessor();        
        element.value = value().toISOString();
    }
};

var viewModel = {    
    MyDate : ko.observable(new Date())
};     

ko.applyBindings(viewModel);

See http://jsfiddle.net/LLkC4/5/


You can use the computed vartiable for the date object in your model:

In html:

<input data-bind="value : rawDate" type="date">

In code:

var currentDate = (new Date()).toISOString().split('T')[0];

// this is used instead of MyDate in the data binding
rawDate : ko.observable(currentDate),

...
// and then set up the dependent variable
viewModel.MyDate = ko.computed(function () {
    var val = this.rawDate();
    if (typeof val === 'string') val = new Date(val);

    return val;
}, viewModel)

Please see the demo: http://jsfiddle.net/gcAXB/1/


Here's a solution that is working for me with the latest knockoutjs, based off of the link below and modified to have a custom init function to handle updating ko.computed properties as your date value changes.

Note that utils.formatDate is just a utility function to format the date in whatever string you want, so just replace that with your own date formatting code, whether you use momentjs or something else.

ko.bindingHandlers.date = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {    
        ko.utils.registerEventHandler(element, 'change', function () {
            var value = valueAccessor();

            if (element.value !== null && element.value !== undefined && element.value.length > 0) {
                value(element.value);
            }
            else {
                value('');
            }
        });
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value = valueAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(value);

        var output = '';
        if (valueUnwrapped !== null && valueUnwrapped !== undefined && valueUnwrapped.length > 0) {
            output = utils.formatDate(valueUnwrapped);
        }

        if ($(element).is('input') === true) {
            $(element).val(output);
        } else {
            $(element).text(output);
        }
    }
};

    <div>
        <label>Date of Birth:</label>
        <input type="text" data-bind="date: dateOfBirth, format: 'DD MMM YYYY'" />
    </div>

BINDING AND FORMATTING DATES USING KNOCKOUT AND MOMENT JS