John Livermore
John Livermore

Reputation: 31343

How to bind jQuery UI option to a Knockout observable

This fiddle shows how to bind a jQuery slider 'slide' event to a Knockout observable. How would this need to change to also bind the 'max' option of the slider to an observable? Do you have to create an entirely new ko.bindingsHandler entry? Or can the existing one be used?

Here is the code from the fiddle for reference.

HTML

<h2>Slider Demo</h2>

Savings: <input data-bind="value: savings, valueUpdate: 'afterkeydown'" />
<div style="margin: 10px" data-bind="slider: savings, sliderOptions: {min: 0, max: 100, range: 'min', step: 1}"></div>

Spent: <input data-bind="value: spent, valueUpdate: 'afterkeydown'" />
<div style="margin: 10px" data-bind="slider: spent, sliderOptions: {min: 0, max: 100, range: 'min', step: 1}"></div>

Net: <span data-bind="text: net"></span>

JS

ko.bindingHandlers.slider = {
  init: function (element, valueAccessor, allBindingsAccessor) {
    var options = allBindingsAccessor().sliderOptions || {};
    $(element).slider(options);
    ko.utils.registerEventHandler(element, "slidechange", function (event, ui) {
        var observable = valueAccessor();
        observable(ui.value);
    });
    ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
        $(element).slider("destroy");
    });
    ko.utils.registerEventHandler(element, "slide", function (event, ui) {
        var observable = valueAccessor();
        observable(ui.value);
    });
  },
  update: function (element, valueAccessor) {
    var value = ko.utils.unwrapObservable(valueAccessor());
    if (isNaN(value)) value = 0;
    $(element).slider("value", value);

  }
};


var ViewModel = function() {
    var self = this;

    self.savings = ko.observable(10);
    self.spent = ko.observable(5);
    self.net = ko.computed(function() {
        return self.savings() - self.spent();
    });
}

ko.applyBindings(new ViewModel());

Upvotes: 1

Views: 5915

Answers (2)

Anders
Anders

Reputation: 17564

I have a collection of jQUery Ui bindings for KO. I havent done the slider because I havent needed that control in a project. But check my button binding

https://github.com/AndersMalmgren/Knockout.Bindings

ko.bindingHandlers.button = {
    initIcon: function (options) {
        if (options.icon) {
            options.icons = { primary: options.icon };
        }
    },
    init: function (element, valueAccessor) {
        var options = ko.utils.unwrapObservable(ko.toJS(valueAccessor())) || {};
        ko.bindingHandlers.button.initIcon(options);

        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            $(element).button("destroy");
        });

        $(element).button(options);
    },
    update: function (element, valueAccessor) {
        var options = ko.toJS(valueAccessor());
        ko.bindingHandlers.button.initIcon(options);

        if (options) {
            $(element).button(options);
        }
    }
};

The magic is done in the update function, KO will by default subscribe to all observables in a object literal, so if you bind to { max: aObservable } the update function will trigger when any child updates.

I then do ko.toJS(valueAccessor()); to un observify the object and use that to update the jQuery control. This method can be used for slider as well, its generic and you do not need to add extra code for each setting

Upvotes: 2

Sławomir Rosiek
Sławomir Rosiek

Reputation: 4073

Look at this fiddle. I added checking if max is observable and subscribing to it:

if (ko.isObservable(options.max)) {
    options.max.subscribe(function(newValue) {
        $(element).slider('option', 'max', newValue);
    });
    options.max = ko.utils.unwrapObservable(options.max);
}

Upvotes: 3

Related Questions