Saturday, February 13, 2016

Creating a Derived Knockout Binding

public class Person
{
    [DataType(DataType.Date)]
    [Column(TypeName = "Date")]
    public DateTime DateOfBirth {get;set;}
}
When returning a Person object from a WebAPI, the JSON looks like:
{
  DateOfBirth: "1990-01-01T00:00:00"
}
When trying to bind this to a date input type using Knockout.js
  <input data-bind="value: DateOfBirth" type="date" />
you will notice that the rendering of the control is the one used when the value is not set and is not initialized properly.

I figured I could update the view model that does the fetching to replace all date string before loading model types or create a binding that handled the possibility of this date format.

I decided to try the latter and create a binding that works similar to the value binding except that it first checks the format of the date input string and updates it to one that works with the date input type.
ko.bindingHandlers.dateValue = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        if (/^\d\d\d\d-\d\d-\d\d(T\d\d:\d\d:\d\dZ?)?/.test(valueAccessor()())) {
            valueAccessor()((valueAccessor()() || "").substr(0, 10));
        }

        ko.bindingHandlers.value.init(element, valueAccessor, allBindings, viewModel, bindingContext);
    },
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        ko.bindingHandlers.value.update(element, valueAccessor, allBindings, viewModel, bindingContext);
    }
}
In the above example, I assume that the binding will be applied to date input types and that the model property is an observable containing the date.  In the init function, I simply get the value from the value accessor and test it's format.  If it matches, I convert to the format required by date input types by simply taking a sub string.   Then I call the value binding's init function, passing along all the parameters.  In the update, I simply call the value binding's update function, passing along all the parameters.

In the knockout documentation, they describe a way to register a preprocessor function on existing bindings, but this method effectively creates a derived binding, similar to how a derived class would be created.  This could also be considered a wrapper around the existing value binding.

This was simpler than I thought it would be!

No comments:

Post a Comment