Search code examples
javascripthtmljquery

Input range slider with different step value


I want to have step from 1 to max and if <=1 , range should have step value of 0.1, I used .prop method and other logic.

This is my full code

 $(document).on("input change", ".slider", function() {
          var val = $(this).val();
          var isdeci = $(this).data("isdeci");
          changeSlide(val, isdeci, $(this));
          //  saveSettings(val, name);
        });

        function changeSlide(val, isdeci, elem) {
          if (isdeci) {
            if (val < 1) {
              elem.prop("step", 0.1);
              elem.prop("min", 0.1);

            } else {
              elem.prop("step", 1);
              if (val % 1 != 0 && val > 1) {
                val = parseInt(val);
                elem.val(val);
              }
            }
          }
          elem.parent().next().find(".outvalue").text(val);

        }
        //1.plus mins 
        $(document).on('click', '.icon-plus', function() {
          plusminus($(this), "plus");
        });
        $(document).on('click', '.icon-minus', function() {
          plusminus($(this), "minus");
        });

        function plusminus(elem, type) {
          var parent = elem.parent().prev().find("input");
          let isdeci = parent.data('isdeci');
          let max = parent.prop('max');
          let min = parent.prop('min');

          let valx = parent.val();
          let step = parent.attr('step');

          if (type == "plus") {
            val = parseFloat(step) + parseFloat(valx);
          } else {
            val = parseFloat(valx) - parseFloat(step);
          }

          if (val < 0.1) {
            val = 0.1;
          }
          if (val >= 1 && val % 1 == 0) {
            val = parseInt(val);
          }
          parent.val(val);
          changeSlide(val, isdeci, parent);
        }

Here I am calling changeSlide, when plus minus is clicked or range slider is moved.

enter image description here

<div class="section">

    <span class="one">sl : </span> 
    <span class="two"><input data-isdeci="1" class="slider" id="sl" type="range" value="4" min="0.1" max="201" step="0.1" /> </span>
    <span class="icon-minus"></span>
    <span data-type="SL" data-lot="1" class="editquantity outvalue">0.2</span> 
    <span class="icon-plus"></span>

It works fine for plus button, but for minus button, it skips from 1 to 0.1. Is this the correct way or is there an easier range function?


Solution

  • The jump occurs because you haven't changed step according to the direction when the slider is at value 1 (you check (val < 1) only). And yes, there's an easier way, something like the example below.

    In the example I've decreased the range of the slider to 5, that way it's easier to see the decimal values when dragging the slider, it'll work with the maximum value of 201 too. Also, due to how min attribute value affects on the actual value of the input together with step value, step is set to 0.1 from the beginning, and new slider values are forcibly calculated instead of changing the step value of the element.

    const buttonWrapper = document.body.querySelector('#buttons'),
      slider = document.body.querySelector('#rangeSlider'),
      output = document.body.querySelector('.outvalue');
    
    updateOutput(+slider.value);
    
    function updateOutput(text) {
      output.textContent = text.toFixed(1);
    }
    
    function updateSlider(e) {
      let val = +slider.value;
      if (e.type === 'click') {
        if (!e.target.matches('[data-dir]')) {return;} // Quit, not clicked on +/- button
        let dir = +e.target.getAttribute('data-dir'),
          step = (val < 1 || (val === 1 && dir < 0)) ? 0.1 : 1;
        val = val + step * dir;
      }
      let newValue = (val > 1) ? Math.round(val) : val;
    
      slider.value = newValue;
      updateOutput(+slider.value);
    }
    
    buttonWrapper.addEventListener('click', updateSlider);
    slider.addEventListener('input', updateSlider);
    .outvalue {
      display: inline-block;
      width: 40px;
      border: 1px solid #000;
      margin: 5px;
      padding: 2px;
      text-align: right;
    }
    <input type='range' min='0.1' max='5' value='2' step="0.1" id='rangeSlider' class='slider' />
    <div id="buttons">
      <button data-dir='-1' class='prev'>-</button>
      <span class="outvalue"></span>
      <button data-dir='1' class='next'>+</button>
    </div>

    Notice how step is conditionally defined when clicking a button. When the slider gets to 1 from the right side ((val === 1 && dir < 0) passes), you've to reduce step too, otherwise newValue jumps to 0.1 directly.

    If you're going to use newValue somewhere else in your code, you've to limit the values to fit to the range, the view value in the example is limited by the input element only, the JS value is not limited.

    The example is written with vanilla JS, but as you seem to use jQuery, you can use this "translated" example.