Bootstrap datepicker and Knockout Model Binding






4.82/5 (5 votes)
Bootstrap datepicker and Knockout Model Binding
Introduction
Now a days, client side MVVM is a popular pattern using knockout.js. But the problem comes when we try to deal with date-time pickers and View Model binding. We can solve such problems using custom blinding handlers for knockout.
Background
I am working new with Knockout and MVVM. Everything was just fine except the date binding from a bootstrap date-time picker/ date time object send from server end. After Googling for sometime, I got a solution, which I am going to demonstrate here. Before we start, we need some .js libraries like:
- jquery
- bootstrap-datepicker
- knockout
- moment (really a good and simple js lib to deal with date time objects)
Using the Code
Let's start with the basic HTML to hold our date-time picker. Here two things are quite important:
data-date-format
: to point format of the date pickerdatepicker
: which is a custom binding handler work for data binding, like value: in regular knockout
<!--date inputed from client-->
<div>
<label class="control-label">Date From Client</label>
<input type="text" readonly="readonly"
data-date-format="dd-mm-yyyy" class="datepicker"
data-bind="datepicker: dateFromClient" />
<span class="help-block">Date with Formate of (dd-mm-yyyy)</span>
</div>
<!--date from server end-->
<div>
<label class="control-label">Date From server</label>
<input type="text" readonly="readonly"
data-date-format="dd-mm-yyyy" class="datepicker"
data-bind="datepicker: dateFromServer" />
<span class="help-block">ClientDate - 5 days, (dd-mm-yyyy)</span>
</div>
The custom binding handler datepicker
is declared like this. We can customize it even for the jquery date time picker if we want to.
/*Date picker value binder for knockout*/
ko.bindingHandlers.datepicker = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = allBindingsAccessor().datepickerOptions || {};
$(element).datepicker(options).on("changeDate", function (ev) {
var observable = valueAccessor();
observable(ev.date);
});
},
update: function (element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
$(element).datepicker("setValue", value);
}
};
Now, we are going to use some utility functions to use moment.js to get current date time or to convert a server side datetime
object to a given date format for client end.
/*Datetime issues with moment =>*/
function currentDate() {
return moment(); //sends current datetime
};
function clientDateStringFromDate(date) {
return moment(date).format('DD-MM-YYYY'); //converts a date object to a given formate
};
Now, here is the View model for our view:
/*View model*/
function ViewModel() {
var self = this;
self.dateFromClient = ko.observable(currentDate()); //set current date to date picker
self.dateFromServer = ko.observable(currentDate()); //set current date to date picker
self.init = function() {
self.getServerDate();
};
self.getServerDate = function () {
var json = JSON.stringify({ date: self.dateFromClient()}); //serialize json to post
$.ajax({
url: '../../Services/DateTestService.asmx/GetDate',
dataType: "json",
contentType: 'application/json; charset=utf-8',
type:"POST",
data:json,
async: true,
processData: false,
cache: false,
success: function (data) {
//alert(data.d); //see what type of data we get
var date = clientDateStringFromDate(data.d); //convert datetime object to date string.
self.dateFromServer(date);
},
error: function (xhr) {
alert('Error to connect to server.');
}
});
};
/*date inputed from client, change event*/
self.dateFromClient.subscribe(function(newValue) {
self.getServerDate();
});
}
Now let's finish with date picker wrapper and model binding.
$(document).ready(function () {
//apply the datepicker to field
$('.datepicker').datepicker();
//model binding
var vm = new ViewModel();
vm.init(); //initialize the view model
ko.applyBindings(vm);
});
I have demonstrated the basic date binding here. You can find more details in the project attachment, which is a Visual Studio 2010 solution.