3

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.

Community
  • 1
  • 1
woggles
  • 7,444
  • 12
  • 70
  • 130
  • The problem is that [this function](https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.slider.js#L505) 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 Mar 07 '13 at 12:56
  • 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 Mar 07 '13 at 13:05
  • Might not be too bad. I'll see if I can come up with something :) – Andrew Whitaker Mar 07 '13 at 13:05

2 Answers2

1

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.

Community
  • 1
  • 1
Paul Manzotti
  • 5,107
  • 21
  • 27
1

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/

Andrew Whitaker
  • 124,656
  • 32
  • 289
  • 307
  • Thanks Andrew...does the trick! Is there any way to stop the slider from resizing though? – woggles Mar 07 '13 at 13:29
  • @woggles: Whoops, didn't even notice that... lets see – Andrew Whitaker Mar 07 '13 at 13:30
  • Actually it doesn't matter in my case because the slider is set to 100% of the width of its enclosing div...though it might create some interesting usability scenarios in other cases :) – woggles Mar 07 '13 at 13:33
  • Unfortunately the code that sets the width of the slider is buried in another function--I'd have to override that one too I think – Andrew Whitaker Mar 07 '13 at 13:35
  • oooh, that sounds like it'll end up being pretty complicated...I think Pauls answer where he adjusts the min or max of the slider ma be a better solution – woggles Mar 07 '13 at 13:44