Search code examples
knockout.jsknockout-es5-plugin

How to access the observables in custom bindings when using Knockout-ES5


If the model properties are ko.observable(), these can be accessed as below within the custom binding.

var observable = valueAccessor();

When using Knockout-ES5 plugin how to get hold of the observable within the custom binding? Check the code below and look for comment "How to get propertyName here?"

JS Fiddle when not using Knockout-ES plugin courtesy of Another Look at Custom Bindings for KnockoutJS

Updated fiddle with model changed to use Knockout-ES plugin

ko.bindingHandlers.datepicker = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
        //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();
            if (!ko.isObservable(observable)) {                
                console.log("Not Observable");
                //How to get propertyName here?
                //ko.getObservable(viewModel, 'propertyName');
                return;
            }
            observable($(element).datepicker("getDate"));
        });

        //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.utils.unwrapObservable(valueAccessor()),
            current = $(element).datepicker("getDate");

        if (value - current !== 0) {
            $(element).datepicker("setDate", value);   
        }
    }
};

var viewModel = {
    myDate: new Date("11/01/2011"),
    setToCurrentDate: function() {
       this.myDate = new Date();   
    }
};

ko.track(viewModel);

ko.applyBindings(viewModel);

Solution

  • You could pass the actual observable to the binding:

    data-bind="datepicker: ko.getObservable($data, 'myDate') ..."
    

    http://jsfiddle.net/xb6vR/1/

    But that's ugly. Fortunately, Knockout does provide a way (undocumented) to write to a property value from a binding:

    //handle the field changing
    ko.utils.registerEventHandler(element, "change", function () {
        var writable = valueAccessor();
        if (!ko.isObservable(writable)) {                
            var propWriters = allBindingsAccessor()._ko_property_writers;
            if (propWriters && propWriters.datepicker) {
                writable = propWriters.datepicker;
            } else {
                return;
            }
        }
        writable($(element).datepicker("getDate"));
    });
    

    http://jsfiddle.net/xb6vR/3/