Antonios Tsimourtos
Antonios Tsimourtos

Reputation: 1682

How to group input type range and keep 100% the max value of all ranges combined together

I have been trying to create 4 input type ranges which the sum of all those (4) have a sum of 100. For example:

Range 1 : 20%
Range 2 : 20%
Range 3 : 20%
Range 4 : 40%

If i drag the value of Range 4 to 50% i expect the below result:

Range 1 : 20%
Range 2 : 20%
Range 3 : 10% (last/previous range that was dragged)
Range 4 : 50%

The general concept :

I have an array which holds the id's of all type ranges. This array is being created on page load - so when the page loads the array looks like this :

["fitness-range","social-range","gourmet-range","street-range"]

Code :

var current_total_percentage = 0; // To have the total percentage
var slider_indexes = []; // The array which holds the id's of type ranges

// Loop each type range and add it's value to the total percentage
jQuery('input[type=range]').each(function (index, value) {
    current_total_percentage += parseInt(jQuery(this).val());
    slider_indexes.push(jQuery(this).attr("id")); // Add the id to the array

});

Everytime an input range is dragged i move it's ID to the first position of that array to know which range was dragged lastly => that means if another range is increased or decreased the lastly range should change value.

Function to move :

arraymove(slider_indexes, slider_indexes.indexOf(jQuery(this).attr("id")), 0);

function arraymove(arr, fromIndex, toIndex) {
    var element = arr[fromIndex];
    arr.splice(fromIndex, 1);
    arr.splice(toIndex, 0, element);
}

I have tried a lot of things but it pretty challenging to make it work so any hints would be appreciated.

NOTES :

1) The step of the range value to be changed by 10. That means everytime a range's value is changed it goes +10 or -10.

2) When decreasing a range i want to decrease/increase the lastly dragged range by 10 in order to always have 100%.

3) If one range is dragged up to 100% all other ranges must become 0%, same row that appear that moment in array.

EDIT 1 : My solution until now -> https://jsfiddle.net/7q569ugo/10/ , it doesnt work if you drag the ranges too fast, or click on the lines of the ranges.

Upvotes: 2

Views: 2621

Answers (3)

stha_sadin
stha_sadin

Reputation: 1

This code creates two tables with two range inputs and two number inputs in each table. The range inputs and number inputs are linked, meaning that changing the value of one will update the value of the other. The code also displays the total of the values of the range inputs in each table.

To create the range inputs and number inputs, the code uses the HTML "input" element with the "type" attribute set to "range" or "number". The 'value', 'min', and 'max' attributes are also set for each input element.

The JavaScript functions "updateTotalTable1" and "updateTotalTable2" are called when the value of a range input is changed, using the "oninput" event. These functions calculate the total of the values of the range inputs in each table by looping through the range inputs and adding their values. The total is then displayed in a "span" element with the corresponding "id".

The "updateInputNumber" and "updateRangeInput" functions are called when the value of a number input is changed, also using the "oninput" event. These functions update the value of the corresponding range input or number input, respectively.

The CSS in the code styles the tables and inputs to take up 50% of the width of the page and to be centered. The range inputs are given a width of 100%.

Finally, the code calls the "updateTotalTable1" and "updateTotalTable2" functions to initialize the total display when the page loads.

HTML:

    <table id="table1">
  <tr>
    <td>
      <input type="range" id="range1" value="50" min="0" max="100" oninput="updateTotalTable1(this); updateInputNumber(this)">
      <input type="number" id="number1" value="50" min="0" max="100" oninput="updateRangeInput(this)">
    </td>
    <td>
      <input type="range" id="range2" value="50" min="0" max="100" oninput="updateTotalTable1(this); updateInputNumber(this)">
      <input type="number" id="number2" value="50" min="0" max="100" oninput="updateRangeInput(this)">
    </td>
  </tr>
</table>
<p>Total for Table 1: <span id="total1"></span></p>
<table id="table2">
  <tr>
    <td>
      <input type="range" id="range3" value="50" min="0" max="100" oninput="updateTotalTable2(this); updateInputNumber(this)">
      <input type="number" id="number3" value="50" min="0" max="100" oninput="updateRangeInput(this)">
    </td>
    <td>
      <input type="range" id="range4" value="50" min="0" max="100" oninput="updateTotalTable2(this); updateInputNumber(this)">
      <input type="number" id="number4" value="50" min="0" max="100" oninput="updateRangeInput(this)">
    </td>
  </tr>
</table>
<p>Total for Table 2: <span id="total2"></span></p>

    enter code here<table id="table1">
  <tr>
    <td>
      <input type="range" id="range1" value="50" min="0" max="100" oninput="updateTotalTable1(this); updateInputNumber(this)">
      <input type="number" id="number1" value="50" min="0" max="100" oninput="updateRangeInput(this)">
    </td>
    <td>
      <input type="range" id="range2" value="50" min="0" max="100" oninput="updateTotalTable1(this); updateInputNumber(this)">
      <input type="number" id="number2" value="50" min="0" max="100" oninput="updateRangeInput(this)">
    </td>
  </tr>
</table>
<p>Total for Table 1: <span id="total1"></span></p>
<table id="table2">
  <tr>
    <td>
      <input type="range" id="range3" value="50" min="0" max="100" oninput="updateTotalTable2(this); updateInputNumber(this)">
      <input type="number" id="number3" value="50" min="0" max="100" oninput="updateRangeInput(this)">
    </td>
    <td>
      <input type="range" id="range4" value="50" min="0" max="100" oninput="updateTotalTable2(this); updateInputNumber(this)">
      <input type="number" id="number4" value="50" min="0" max="100" oninput="updateRangeInput(this)">
    </td>
  </tr>
</table>
<p>Total for Table 2: <span id="total2"></span></p>

CSS:

table {
  width: 50%;
  margin: 0 auto;
}

td {
  width: 50%;
}

input[type="range"] {
  width: 100%;
}

JS:

function updateTotalTable1(rangeInput) {
    let total = 0;
    let ranges = document.querySelectorAll("#table1 input[type='range']");
    ranges.forEach(function(range) {
      total += parseInt(range.value);
    });
  
    // Update the total display
    document.getElementById("total1").innerHTML = total;
  
    // Check if the total is at the maximum value and prevent the user from increasing the value of the range input if it is
    if (total >= 100) {
      rangeInput.value = Math.min(rangeInput.value, 100 - (total - rangeInput.value));
    }
  }
  
  function updateTotalTable2(rangeInput) {
    let total = 0;
    let ranges = document.querySelectorAll("#table2 input[type='range']");
    ranges.forEach(function(range) {
      total += parseInt(range.value);
    });
  
    // Update the total display
    document.getElementById("total2").innerHTML = total;
  
    // Check if the total is at the maximum value and prevent the user from increasing the value of the range input if it is
    if (total >= 100) {
      rangeInput.value = Math.min(rangeInput.value, 100 - (total - rangeInput.value));
    }
  }
function updateInputNumber(rangeInput) {
  let inputNumber = document.getElementById(rangeInput.id.replace("range", "number"));
  inputNumber.value = rangeInput.value;
}
function updateRangeInput(inputNumber) {
  let rangeInput = document.getElementById(inputNumber.id.replace("number", "range"));
  rangeInput.value = inputNumber.value;
   // Update the total value for the corresponding table
  if (inputNumber.id.startsWith("number")) {
    updateTotalTable1(rangeInput);
  } else {
    updateTotalTable2(rangeInput);
  }
}

 // Initialize the total display
  document.addEventListener("DOMContentLoaded", function() {
    updateTotalTable1();
    updateTotalTable2();
   
  });

Upvotes: 0

umer
umer

Reputation: 1316

I have not tested this code , but you can have the basic idea of the solution to your problem. Moreover , you just not need to remember only the previously moved slider, you have to remember all of the sliders in previously moved order.

$(document).ready(function(){

var slider_indexes = [];
var i=1;
jQuery('input[type=range]').each(function (index, value) {

var RangeId=jQuery(this).attr("id");
var RangeVal=jQuery(this).val();
var RangeInfoObject= 
{"RangeId":""+RangeId+"","RangeVal":""+RangeVal+"","DragOrder":""+i+""}
slider_indexes.push(RangeInfoObject); // Add the object to the array
i++;
});

$("[type=range]").change(function(){
var DarggedId=$(this).attr("id");
var newval=$(this).val();
var RangeInfoObject=slider_indexes.find(x => x.RangeId==DarggedId);

var PreviousVal=parseInt(RangeInfoObject.RangeVal);
var PreviousDragOrder=parseInt(RangeInfoObject.DragOrder);
var flag=0;
    $.each(slider_indexes, function(i, item) {
       if(item.RangeId==DarggedId)
       {
          item.DragOrder=1;
          item.RangeVal=newval;
       }
       else
       {
           if(parseInt(item.DragOrder)<PreviousDragOrder)
           {
              item.DragOrder=parseInt(item.DragOrder)+1;
           }
           if(newval<PreviousVal && flag==0)
           {  
              if(item.RangeVal<100)
              {
                  item.RangeVal=parseInt(item.RangeVal)+10;
                                  $("#"+item.RangeId).val(parseInt(item.RangeVal));
                  flag=1;
              }
           }
           else if(newval>PreviousVal && flag==0)
           { 
              if(item.RangeVal>9)
              {
                  item.RangeVal=parseInt(item.RangeVal)-10;
                  $("#"+item.RangeId).val(parseInt(item.RangeVal));
                  flag=1;
              }

           }
       }
    });
    //Here you need to sort slider_indexes e.g Order by DragOrder
    slider_indexes.sort(function(obj1, obj2) {

        return parseInt(obj1.DragOrder)- parseInt(obj2.DragOrder);
    });
  });
});

Here is the fiddle. https://jsfiddle.net/mian_umer/m15g9nky/

Upvotes: 0

offwhite
offwhite

Reputation: 552

I think it would be easier for you to calculate the difference on the current slider and then apply that difference to the previous slider.

var current_value = parseInt($(this).val());
var previous_value = parseInt($(this).data('previous-value'));
var difference = current_value - previous_value;

Then you have to handle if the previous slider is out of bounds (below 0 or over 100).

https://jsfiddle.net/htd8x2jz/1/

I'm afraid that's not the cleanest fail-to-the-next-slider solution, it should really be a method that loops through the array til it returns what slider should be updated. But the jsfiddle should be enough to get you on the way.

Personally I'd recommend all other sliders adjust when dragging one, the way you've described would make it very difficult to set them all to 25% for example. I appreciate that was not your question, but I thought I'd mention it.

Upvotes: 1

Related Questions