Detilium
Detilium

Reputation: 3026

Knockout not populating DateTime? when initial is null

I'm using knockout to bind my view model to my view. Multiple properties in my view model are nullable, such as DateTime?s. Here's an example:

public class ViewModel
{
    public int ID { get; set; }
    public string Name { get; set; }
    public DateTime? CreationDate { get; set;}
}

As you can see, the property CreationDate is a nullable DateTime.

I'm binding the property with a custom datepicker binder:

ko.bindingHandlers.datepicker = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        try {
            var jsonDate = ko.utils.unwrapObservable(valueAccessor());
            var value = parseJsonDateString(jsonDate);
            var strDate = value.getMonth() + 1 + "/"
                            + value.getDate() + "/"
                            + value.getFullYear();
            element.setAttribute('value', strDate);
        }
        catch (exc) {
        }
        $(element).change(function () {
            var value = valueAccessor();
            value(element.getAttribute('value'));
        });
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var val = valueAccessor();
        val(element.getAttribute('value'));
    }
};

var jsonDateRE = /^\/Date\((-?\d+)(\+|-)?(\d+)?\)\/$/;
var parseJsonDateString = function (value) {
    var arr = value && jsonDateRE.exec(value);
    if (arr) {
        return new Date(parseInt(arr[1]));
    }
    return value;
};

This enables me to bind my property in the view like so:

<input type="text" data-bind="datepicker: CreationDate" />

Problem

Here's the problem. Sometimes this property is already null when it enters the view. A JSON example could look like this:

{
  "Id": 2004,
  "Name": "Test",
  "CreationDate": null
}

If this is the case, and I change this value to some random value from the datepicker, and send an ajax POST to my controller, I can see that models CreationDate still is equal to null.

So if the DateTime is null as the model enters the view, how do I populate the models property?

Upvotes: 0

Views: 990

Answers (1)

Detilium
Detilium

Reputation: 3026

Found the solution on my own

I managed to solve my issue by simply changing my binding to the following:

ko.bindingHandlers.datepicker = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        //initialize datepicker with some optional options
        var options = allBindingsAccessor().datepickerOptions || {};
        $(element).datepicker(options);

        //handle the field changing
        ko.utils.registerEventHandler(element, "change", function () {
            var observable = valueAccessor();
            var value = $(element).val();
            // if the input field is empty, the value is falsy and therefore the observable should be = null
            if(!value){
                observable(null);
            } else {
                var date = new Date(value);
                observable(date);
            }
        });

        //handle disposal (if KO removes by the template binding)
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            $(element).datepicker("destroy");
        });

    },
    //update the control when the view model changes
    update: function (element, valueAccessor) {
        var value = ko.unwrap(valueAccessor());
        //if the value received is null, we should display nothing in the input field
        if (value === null) {
            $(element).val(null);
        } else {
            //we need to manipulate the data to show something user friendly to the user
            var date = parseJsonDateString(value);
            var strDate = date.getMonth() + 1 + "/"
                                        + date.getDate() + "/"
                                        + date.getFullYear();
            $(element).val(strDate);
        }
    }
};

So basically if the value I'm getting in the update function, simply set $(element).val(null). This way, nullable properties are handled correctly.

Upvotes: 1

Related Questions