skip to Main Content

I want my slider to move only on those possible values, currently, it is possible to place the slider on 60, and in this case it should be 50. I just want to get possible values between 0, 30, 50, and 90.

how can do it?

const inputRange = document.getElementById('inputRange');
  
inputRange.addEventListener('input', function() {
  const valor = inputRange.value;
  textSlider=document.getElementById("textRange");
  textSlider.style.left= valor+"%";
  textSlider.innerText= valor + "%";
});
.rangeWrap{
    border:1px solid red;
    display: inline-block;
    position:relative;
}
#textRange{
    display:block;
    position:absolute;
    left:0px;
    bottom:0px;
    pointer-events: none;
  font-size: 14px;
  line-height: 1;
  text-shadow: none;
  padding: 3px 5px;
  background-color: #006cfa;
  color: white;
  border-radius: 4px;
  
}

#textRange:after{
    content:"";
    position: absolute;
    right: 50%;
    top: -4px;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 0 4px 4px 4px;
    border-color: transparent transparent #006cfa transparent;
    z-index:9998;
}
<section class="rangeWrap">
    
    <input type="range" id="inputRange" value="0" min="0" max="90" step="30" list="ticks" />

    <datalist id="ticks">
        <option value="0" label="0%"></option>
        <option value="30" label="30%"></option>
        <option value="50" label="50%"></option>
        <option value="90" label="90%"></option>
    </datalist>
    <span id="textRange" >0%</span>
</section>

2

Answers


  1. I have inserted the code to dynamically detect which tick is closer to the user’s dragged/current value. I have added comments to explain what I did. Also I removed the step property on input to enable dynamic closest tick value detection.

    const inputRange = document.getElementById('inputRange');
    
    const ticksElement = document.getElementById('ticks');
    // Get ticks datalist element's childrens (options with values as ticks)
    // and extract the tick values as an array such as [0, 30, 50, 90]
    const ticks = Array.from(ticksElement.children)
      .map(option => parseInt(option.value));
    
    inputRange.addEventListener('input', function() {
      const valor = parseInt(inputRange.value);
      // Compute the tick value below/before the dragged value (valor)
      const tickBelow = Math.max(...ticks.filter(tick => tick <= valor));
      // Compute the tick value above/after the dragged value (valor)
      const tickAbove = Math.min(...ticks.filter(tick => tick >= valor));
      // Compute the value distance to below/before tick
      const distanceToTickBelow = Math.abs(valor - tickBelow);
      // Compute the value distance to above/after tick
      const distanceToTickAbove = Math.abs(valor - tickAbove);
      
      // Set a variable to hold the tick value which is closer to dragged value (valor)
      let closestTickValue = 0;
      
      // If distance to tick below/before is less than distance
      // to tick above/after, closest tick value is the one below/before
      // Else distance to tick below/before is greater than or equal to 
      // distance to tick above/after, so closest tick value is
      // the one above/after
      if(distanceToTickBelow < distanceToTickAbove) {
        closestTickValue = tickBelow;
      } else {
        closestTickValue = tickAbove;
      }
      
      // Update input's value with closest tick value
      inputRange.value = closestTickValue;
      
      // Update tooltip element's properties with closest tick value
      textSlider = document.getElementById("textRange");
      textSlider.style.left = closestTickValue + "%";
      textSlider.innerText = closestTickValue + "%";
    });
    .rangeWrap {
      border: 1px solid red;
      display: inline-block;
      position: relative;
    }
    
    #textRange {
      display: block;
      position: absolute;
      left: 0px;
      bottom: 0px;
      pointer-events: none;
      font-size: 14px;
      line-height: 1;
      text-shadow: none;
      padding: 3px 5px;
      background-color: #006cfa;
      color: white;
      border-radius: 4px;
    }
    
    #textRange:after {
      content: "";
      position: absolute;
      right: 50%;
      top: -4px;
      width: 0;
      height: 0;
      border-style: solid;
      border-width: 0 4px 4px 4px;
      border-color: transparent transparent #006cfa transparent;
      z-index: 9998;
    }
    <section class="rangeWrap">
    
      <input type="range" id="inputRange" value="0" min="0" max="90" list="ticks" />
    
      <datalist id="ticks">
            <option value="0" label="0%"></option>
            <option value="30" label="30%"></option>
            <option value="50" label="50%"></option>
            <option value="90" label="90%"></option>
        </datalist>
      <span id="textRange">0%</span>
    </section>
    Login or Signup to reply.
  2. My solution was to just snap the result to one of the allowed values, which is stored in the const allowed. Then you just loop over them in an onchange function and find the nearest one and set the input’s value.

    const inputRange = document.getElementById('inputRange');
    const textSlider = document.getElementById("textRange");
    const allowed = [0, 30, 50, 90];
    
    let diff = 100;
    let newVal = 0;
    inputRange.onchange = function() {
      diff = 100;
      allowed.forEach((val) => {
        let thisDiff = Math.abs(inputRange.value - val);
        if (thisDiff < diff) {
          newVal = val;
          diff = thisDiff;
        }
      });
      inputRange.value = newVal;
    
      textSlider.style.left= newVal+"%";
      textSlider.innerText= newVal + "%";
    }
    .rangeWrap{
        display: inline-block;
        position:relative;
    }
    #textRange{
        display:block;
        position:absolute;
        left:0px;
        bottom:0px;
        pointer-events: none;
      font-size: 14px;
      line-height: 1;
      text-shadow: none;
      padding: 3px 5px;
      background-color: #006cfa;
      color: white;
      border-radius: 4px;
      
    }
    
    #textRange:after{
        content:"";
        position: absolute;
        right: 50%;
        top: -4px;
        width: 0;
        height: 0;
        border-style: solid;
        border-width: 0 4px 4px 4px;
        border-color: transparent transparent #006cfa transparent;
        z-index:9998;
    }
    <section class="rangeWrap">
        
        <input type="range" id="inputRange" value="0" min="0" max="90" step="1" list="ticks" />
    
        <datalist id="ticks">
            <option value="0" label="0%"></option>
            <option value="30" label="30%"></option>
            <option value="50" label="50%"></option>
            <option value="90" label="90%"></option>
        </datalist>
        <span id="textRange" >0%</span>
    </section>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search