Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using knockout js with jquery ui sliders

I'm trying to figure out if knockout js would work nicely for the following problem:

I have multiple sliders that I want to link to textboxes.

When the textbox is changed the corresponding slider must update to the new value and vice versa.

On changing the slider value or textbox a function needs to be called that uses the input from all textboxes to calculate a result.

I have my quick and dirty jQuery solution here.

Would it be easy to achieve the same result in a more elegant way using knockout js?

I guess I would need to create a custom binding handler like its done in jQuery UI datepicker change event not caught by KnockoutJS

like image 698
woggles Avatar asked Oct 12 '12 09:10

woggles


2 Answers

Here is an example: http://jsfiddle.net/jearles/Dt7Ka/

I use a custom binding to integrate the jquery-ui slider and use Knockout to capture the inputs and calculate the net amount.

--

UI

<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>

View Model

ko.bindingHandlers.slider = {
  init: function (element, valueAccessor, allBindingsAccessor) {
    var options = allBindingsAccessor().sliderOptions || {};
    $(element).slider(options);
    $(element).slider({
        "slide": function (event, ui) {
            var observable = valueAccessor();
            observable(ui.value);
        },
        "change": function (event, ui) {
            var observable = valueAccessor();
            observable(ui.value);
        }
    });
    ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
        $(element).slider("destroy");
    });
  },
  update: function (element, valueAccessor) {
    var value = ko.unwrap(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());
like image 134
John Earles Avatar answered Oct 24 '22 13:10

John Earles


I know it's some days ago but I made a few adjustments to John Earles code:

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, allBindingsAccessor) {
    var value = ko.utils.unwrapObservable(valueAccessor());
    if (isNaN(value)) value = 0;
    $(element).slider("option", allBindingsAccessor().sliderOptions);
    $(element).slider("value", value);
}
};

The reason for this is that if you use options that change (fx another observable) then it won't affect the slider even if you wanted it to do so.

like image 38
Michael Kire Hansen Avatar answered Oct 24 '22 15:10

Michael Kire Hansen