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

html, javascript, knockout.js

Solution

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/

Problem

(this only works in Chrome at the moment as most browsers don't yet implement date picker for input type="date") In the following example MyDate starts out as a Date object with the current date, but this isn't picked up by the date input (which expects its format to be a string in format YYYY/MM/DD). Once you've picked a date in the picker then MyDate becomes a string in format above. How can you bind this so MyDate stays a javascript Date and is interpreted by the input control correctly? See See http://jsfiddle.net/LLkC4/3/ :- ``` <input data-bind="value : MyDate" type="date"> <hr> <span data-bind="html: log" /> <script> var viewModel = { MyDate : ko.observable(new Date()), log : ko.observable(""), logDate : function () { this.log(this.log() + this.MyDate() + " : " + typeof(this.MyDate()) + "<br>"); } }; viewModel.MyDate.subscribe(function (date) { viewModel.logDate(); }); ko.applyBindings(viewModel); viewModel.logDate() </script> ```

Original source

Related problems