andreruffert / rangeslider.js

🎚 HTML5 input range slider element jQuery polyfill
https://rangeslider.js.org
MIT License
2.17k stars 401 forks source link

First Range Slider Acting Up If Populating by JS #148

Closed njyo closed 9 years ago

njyo commented 9 years ago

When using a JS function to fill sliders from an object, the first rangeslider seems to display strange behaviour:

  1. It defaults to the middle
  2. It skews the range strongly to the right side

Example code:

<!DOCTYPE html>
<html lang="en">
    <head>
        <script src="http://code.jquery.com/jquery-2.1.4.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/rangeslider.js/1.2.1/rangeslider.min.js"></script>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/rangeslider.js/1.2.1/rangeslider.min.css">
        <style type="text/css">
            .rangeslider {margin-top: 3rem;}
            .slidervalue {text-align: center; margin-top: 1rem;}
        </style>
    </head>
    <body>

        <div><input type="range" id="t-count"/><div class="slidervalue"></div></div>
        <div><input type="range" id="e-count"/><div class="slidervalue"></div></div>
        <div><input type="range" id="g-count"/><div class="slidervalue"></div></div>

        <script>
            var model = {
                t: {values: [1, 2, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 120], index: 0},
                e: {values: [5, 25, 50, 75, 100, 125, 150, 200, 225, 250, 300, 350, 400, 450, 500], index: 0},
                g: {values: [50000, 100000, 150000, 200000, 250000, 500000, 750000, 1000000, 1500000, 2000000, 2500000, 3000000, 4000000, 5000000], index: 7}
            };

            var updateView = function() {
                $("#t-count")[0].max = model.t.values.length-1;
                $("#t-count")[0].step = 1;
                $("#t-count")[0].value = model.t.index;
                $("#t-count ~ .slidervalue")[0].textContent = model.t.values[model.t.index];

                $("#e-count")[0].max = model.e.values.length-1;
                $("#e-count")[0].step = 1;
                $("#e-count")[0].value = model.e.index;
                $("#e-count ~ .slidervalue")[0].textContent = model.e.values[model.e.index];

                $("#g-count")[0].max = model.g.values.length-1;
                $("#g-count")[0].step = 1;
                $("#g-count")[0].value = model.g.index;
                $("#g-count ~ .slidervalue")[0].textContent = model.g.values[model.g.index];
            };

            var updateCalc = function(e) {
                model[e.id.split("-")[0]].index = parseInt(e.value);
                updateView();
            }

            $('input[type="range"]').rangeslider({
                polyfill: false,

                // Default CSS classes
                rangeClass: 'rangeslider',

                // Callback function
                onInit: function() {},

                // Callback function
                onSlide: function(position, value) {
                    updateCalc(this.$element[0]);
                },

                // Callback function
                onSlideEnd: function(position, value) {}
            });
        </script>
    </body>
</html>
andreruffert commented 9 years ago

I guess you wanted to achieve something like this right!?

<!DOCTYPE html>
<html lang="en">
    <head>
        <script src="http://code.jquery.com/jquery-2.1.4.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/rangeslider.js/1.2.1/rangeslider.min.js"></script>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/rangeslider.js/1.2.1/rangeslider.min.css">
        <style type="text/css">
            .rangeslider {margin-top: 3rem;}
            .slidervalue {text-align: center; margin-top: 1rem;}
        </style>
    </head>
    <body>

        <div>
            <input type="range" id="t-count"/>
            <div id="t-output" class="slidervalue"></div>
        </div>
        <div>
            <input type="range" id="e-count"/>
            <div id="e-output" class="slidervalue"></div>
        </div>
        <div>
            <input type="range" id="g-count"/>
            <div id="g-output" class="slidervalue"></div>
        </div>

        <script>
        $(function(){
            var $tCount = $("#t-count");
            var $eCount = $("#e-count");
            var $gCount = $("#g-count");

            var $tOutput = $("#t-output");
            var $eOutput = $("#e-output");
            var $gOutput = $("#g-output");

            var model = {
                t: {values: [1, 2, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 120], index: 0},
                e: {values: [5, 25, 50, 75, 100, 125, 150, 200, 225, 250, 300, 350, 400, 450, 500], index: 0},
                g: {values: [50000, 100000, 150000, 200000, 250000, 500000, 750000, 1000000, 1500000, 2000000, 2500000, 3000000, 4000000, 5000000], index: 7}
            };

            // Set the initial attributes
            var init = function() {
                $tCount[0].max = model.t.values.length-1;
                $tCount[0].step = 1;
                $tCount[0].value = model.t.index;
                $tOutput[0].textContent = model.t.values[model.t.index];

                $eCount[0].max = model.e.values.length-1;
                $eCount[0].step = 1;
                $eCount[0].value = model.e.index;
                $eOutput[0].textContent = model.e.values[model.e.index];

                $gCount[0].max = model.g.values.length-1;
                $gCount[0].step = 1;
                $gCount[0].value = model.g.index;
                $gOutput[0].textContent = model.g.values[model.g.index];
            }();

            var updateModelIndex = function(key, index) {
                model[key].index = parseInt(index);
            };

            $('input[type="range"]')
                .rangeslider({
                    polyfill: false
                })
                .on('input', function(e) {
                    var element = e.target;
                    var key = element.id.split("-")[0];
                    var index = element.value;
                    var output = model[key].values[index];

                    // Update model `index`
                    // If you don't need the `index` later you could remove the update fn.
                    updateModelIndex(key, index);

                    // Update the visible output value
                    $('#' + key + '-output')[0].textContent = output;
                });
        });
        </script>
    </body>
</html>
njyo commented 9 years ago

Thanks, yes, your example seems to work fine here. I'd need to see how I can refactor my (quite a bit more complicated) code to fit this approach, as I do need to do a number of calculations upon change.

Seems like the problem is a race condition un the onSlide method by me updating the value manually…

Thanks for your help.