vank091
vank091

Reputation: 91

how to prevent the user to drag HTML input type='range' right?

I have three input type='range' fields that have different max values but share the same capacity. This capacity is decreased with every change on either of the three inputs. When the capacity reaches 0 I am supposed to prevent the input fields from moving right ( from increasing their value ) and only move left, but I dont know how to do it using JS and jQuery

here is the html for the inputs

<input type="range" class="slider" id="woodSlider" min="0" value="0" max="1558">
<input type="range" class="slider" id="ironSlider" min="0" value="0" max="2555">
<input type="range" class="slider" id="stoneSlider" min="0" value="0" max="2451">

and here is the code that decreases the capacity:

$("input").change(function() {  
    $("#capacityLeft").html(parseInt(holding.capacity) - 
         $("#woodSlider").val() -
         $("#ironSlider").val() -
         $("#stoneSlider").val());
    if(parseInt($("#capacityLeft").html()) <= 0) {
    // TODO: FIND OUT HOW TO STOP THE SLIDERS FROM MOVING
    }
});

Upvotes: 6

Views: 9296

Answers (3)

flen
flen

Reputation: 2386

Just to expand on both answers, in regard to the OP's question // TODO: FIND OUT HOW TO STOP THE SLIDERS FROM MOVING, it must be said that the change event for input type range is not cancelable. Thus, preventDefault etc. won't work on it and you might very quickly see the slide moving first (because it can't be canceled) and then see it moving to the new position JavaScript changed it to.

TL;DR you can't stop the slider from moving, but you can update the value.

Here's an example of what I mean, note that if you click on the slider itself you'll see it quickly moving and then falling back to the JS assigned position:

const example = document.getElementById('example');
example.addEventListener('click', (ev) => {
        // needs this because input change event isn't cancellable, clicking on input will first change input regardless (e.g., it will go from 0 to 1, but then the script will return it to 0)
        const input = example.querySelector('input');
        input.value = input.value === "1" ? "0" : "1";
        ev.preventDefault();
        ev.stopImmediatePropagation();
    }, {capture: true});
<div id="example">
  OFF<input type="range" min="0" max="1">ON
</div>

<div>now click twice directly on one of the range input extremities</div>

That's also why @Andrew's answer above requires a variable to be stored somewhere else recording the state of the input.

Upvotes: 1

Andrew
Andrew

Reputation: 1

I fiddled around for a while, and this is what I was able to custom set the input range's value with (this code basically implements a "toggle" button):

let input = document.getElementById('myInput');
let currentValue = 0;
input.onclick = function(e) {
  currentValue = 1 - currentValue;
  e.target.value = currentValue;
  return false;
}
<input id="myInput" type="range" min="0" max="1" value="0" style="width: 600px;" />

JSFiddle

I used onclick because I wanted it to respond every time the user clicks anywhere on the input range, not just when the user "changes the value" according to the browser. Obviously, use oninput or onchange if you only want to fire an event when the user changes the slider position.

It does appear to be the case that you need to manually set/override the e.target.value as the return false; is not really doing anything. In fact, the above code works just the same without returning false.


For mobile, however, you need to use ontouchstart instead of onclick. You also need to return false; for it to work.

Upvotes: 0

pawel
pawel

Reputation: 36965

Okay, so you can use event.preventDefault() to stop an event. You should bind a function to onchange or oninput events on these range sliders and calculate the sum, check if it exceed the max, then stop the event if it does.

Here's a pure JS solution (fiddle link), could be easily rewritten with jQuery.

var maxTotal = 150, // define the max sum of values
    inputs = [].slice.call(document.getElementsByTagName('input')), // refrence to the elements
    getTotal = function(){ // helper function to calculate the sum
        var sum = 0;
        inputs.forEach( function(input){
           sum += parseInt(input.value, 10); 
        });
        return sum;
    },
    maxReached = function(e){  // check if the max is reached
        var sum = getTotal(), target;
        if(sum > maxTotal){
            target = e.target;
            // set the max possible value if the user, for example, clicks too far to the right
            target.value = target.value - (sum - maxTotal);
            // next line is just for demonstrational purposes
            document.getElementById('total').innerHTML = getTotal();

            // prevent increasing the value
            e.preventDefault();
            return false;
        }
        // next line is just for demonstrational purposes
        document.getElementById('total').innerHTML = getTotal();

        // everything's fine, nothing to do.
        return true;
    };

// attach the maxReached function to your inputs
inputs.forEach( function(input){
    input.addEventListener('input', maxReached );
});

Upvotes: 11

Related Questions