3
votes

I have a jquery ui slider that is linked to a numerical textbox. The slider has a max and min value.

See ui slider with text box input or Using knockout js with jquery ui sliders for a knockout js implementation.

My question is: is it possible to set the value of the slider to above the max or below the min?

If value is outside the range it is set to the max or min of the range:

$(element).slider("value", value);

So for example, say the slider represents the percentage of your monthly salary between 50 and 100. Monthly salary is set to 10000. If you slide the slider it will vary from 5000 to 10000, but I still want users to be able to input values outside of the range. So if the user inputs 12000 the slider will slide to max, and if the user inputs 2000 the slider will slide to the min.

2
The problem is that this function is called, which will force the value you assign the slider to fit within the min and max ranges. The short answer is "no, it's not possible to set a value on the slider outside of its range" unless you're open to overriding the function I linked to.Andrew Whitaker
How easy is it to override that function? I assumed that extending the jquery-ui library might be the only way it would be possible to achieve this.woggles
Might not be too bad. I'll see if I can come up with something :)Andrew Whitaker

2 Answers

1
votes

You can accomplish this by overriding the _trimAlignValue function that I noted in my comment:

$.ui.slider.prototype._trimAlignValue = function (val) {
    var step = (this.options.step > 0) ? this.options.step : 1,
        valModStep = val % step,
        alignValue = val - valModStep;

    if (Math.abs(valModStep) * 2 >= step) {
        alignValue += (valModStep > 0) ? step : (-step);
    }
    return parseFloat(alignValue.toFixed(5));
};

This will effect every slider on the page--if this isn't the desired effect you should wrap this functionality in your own plugin (I can provide an example that does that too, if need be).

This combined with your existing KnockoutJS custom binding seems to work well.

Example: http://jsfiddle.net/Aa5nK/7/

1
votes

Adapted from the answer in Using knockout js with jquery ui sliders

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

And here's the custom binding:

ko.bindingHandlers.slider = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        var options = allBindingsAccessor().sliderOptions || {};
        $(element).slider(options);
        ko.utils.registerEventHandler(element, "slidechange", function (event, ui) {
            var value = valueAccessor();
            if(!(value < $(element).slider('option', 'min')   || value > $(element).slider('option', 'max')))
            {
            valueAccessor(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;
        if (value < $(element).slider('option', 'min')) {
            value = $(element).slider("option", "min");
        } else if (value > $(element).slider('option', 'max')) {
            value = $(element).slider("option", "max");
        }
        $(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());

I adapted the jsFiddle from that answer too.