woggles
woggles

Reputation: 7444

Allow setting of jquery ui slider to above max value or below the min value

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.

Upvotes: 3

Views: 1183

Answers (2)

Paul Manzotti
Paul Manzotti

Reputation: 5147

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.

Upvotes: 1

Andrew Whitaker
Andrew Whitaker

Reputation: 126072

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/

Upvotes: 1

Related Questions