Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

(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>
like image 298
Ryan Avatar asked Aug 02 '13 12:08

Ryan


People also ask

What is binding in knockout JS?

A binding context is an object that holds data that you can reference from your bindings. While applying bindings, Knockout automatically creates and manages a hierarchy of binding contexts. The root level of the hierarchy refers to the viewModel parameter you supplied to ko. applyBindings(viewModel) .

How do I use knockout js in HTML?

It is very easy to use KnockoutJS. Simply refer the JavaScript file using <script> tag in HTML pages. A page as in the following image will be displayed. Click on download link and you will get the latest knockout.

Are there any style options for the HTML5 date picker?

Currently, there is no cross browser, script-free way of styling a native date picker.

What is two-way binding in knockout JS?

KO is able to create a two-way binding if you use value to link a form element to an Observable property, so that the changes between them are exchanged among them. If you refer a simple property on ViewModel, KO will set the form element's initial state to property value.


2 Answers

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/

like image 81
Ryan Avatar answered Sep 28 '22 10:09

Ryan


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/

like image 45
amakhrov Avatar answered Sep 28 '22 08:09

amakhrov