0

All,

Environment:

asp.net 3.5

My dates are serialized using ISO8601 format via lib: Newtonsoft.json library

Objective:

Create 2-way binding between a date field on my model (Document.DocumentDate) and the textbox of the ajax control toolkit calendar extender. The ajax calendar uses a text field behind the scenes so I apply the binding below to the text field. When the page loads, the binding from object to control works but after I change the text field using the calendar extender, the text value is changed but my underlying object is not updated, neither the update() method on the binding is called.

Here's the code:

data-bind="date: {jsonDate : Document.DocumentDate }" 

ko.bindingHandlers.date = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value = valueAccessor();
        var dtStr = ko.unwrap(value.jsonDate);

        var dt = new Date(dtStr);

        var ret = dt.getMonth() + 1 + "/" + dt.getDate() + "/" + dt.getFullYear();
        $(element).val(ret);
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
    }
};

NOTE:

If I change my data-bind expression to:

data-bind="value: Document.DocumentDate"

Everything works fine but the date gets rendered not the way I wanted in the text field. That's why I resorted to custom binding to format the date in the text field.

ActiveX
  • 1,064
  • 1
  • 17
  • 37

2 Answers2

0

You can use extenter to format date (Knockout.js format date item)

or you can wrap the "value" binding with formatting function for editable case:

// Formatted value accessor creator

function createValueAccessor(dateValue) {
  return function() {
    return ko.computed({
     read: function() {
       var dtStr = ko.unwrap(dateValue);
       var dt = new Date(dtStr);
       return dt.getMonth() + 1 + "/" + dt.getDate() + "/" + dt.getFullYear();
     },
      write: function(newValue) { dateValue(newValue); }
    });
  }
}

// Binding handler

ko.bindingHandlers.dateValue = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value = valueAccessor();
        ko.bindingHandlers.value.init(element, createValueAccessor(value), allBindingsAccessor, viewModel);
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value = valueAccessor();
        ko.bindingHandlers.value.update(element, createValueAccessor(value), allBindingsAccessor, viewModel);
    }
};

// Sample part

var viewModel = { date: ko.observable("1.1.15") };
viewModel.date.subscribe(function(newVal) {
 alert(newVal.toString());
});

ko.applyBindings(viewModel);

setTimeout(function() { viewModel.date("12.12.15") }, 1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<input data-bind="dateValue: date" />
Community
  • 1
  • 1
TSV
  • 7,538
  • 1
  • 29
  • 37
0

Here's a working solution:

datePicker: {{ jsonDate: Document.DocumentDate, format: 'dd-MMM-yyyy' }}

   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();
            var dtStr = element.value;
            var fmt = ko.unwrap(value.format);

            var dt = Date.parseLocale(dtStr, fmt)
            value.jsonDate(dt);
        });
    },
    // Update the control whenever the view model changes
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value = valueAccessor();
        var dtStr = ko.unwrap(value.jsonDate);
        var fmt = ko.unwrap(value.format);

        element.value = new Date(dtStr).localeFormat(fmt);
    }
};

Based on posts here: Using Knockout.js how do bind a Date property to a HTML5 date picker?

Community
  • 1
  • 1
ActiveX
  • 1,064
  • 1
  • 17
  • 37