jQuery UI Slider - how to use multiple sliders in a page

1.5k Views Asked by At

I am trying to create multiple slide bar with jquery ui slider. Problem is the value change in the last bar only when slide on the other bars. When slide on the other slide bar value change in the last bar only. Fiddle link

function collision($div1, $div2) {
      var x1 = $div1.offset().left;
      var w1 = 40;
      var r1 = x1 + w1;
      var x2 = $div2.offset().left;
      var w2 = 40;
      var r2 = x2 + w2;
        
      if (r1 < x2 || x1 > r2) return false;
      return true;
      
    }
    
// // slider call
var search_type = ['id1','id2','id3','id4'];
for(var i = 0; i<search_type.length; i++){
var ids = '#' + search_type[i] + '-range';
var $this = '#'+search_type[i]+'-c';
console.log($this);
console.log(ids);
$(ids).slider({
 range: true,
 min: 0,
 max: 500,
 values: [ 75, 300 ],
 slide: function(event, ui) {
  
  $(ids +' .ui-slider-handle:eq(0) .price-range-min').html(ui.values[ 0 ]);
  $(ids +' .ui-slider-handle:eq(1) .price-range-max').html( ui.values[ 1 ]);
  $(ids +' .price-range-both').html('<i>' + ui.values[ 0 ] + ' - </i>' + ui.values[ 1 ] );
  console.log(ids +' .ui-slider-handle:eq(1) .price-range-max');
  //
  
    if ( ui.values[0] == ui.values[1] ) {
      $(ids+' .price-range-both i').css('display', 'none');
    } else {
      $(ids+' .price-range-both i').css('display', 'inline');
    }
        
        //
  
  if (collision($('.price-range-min'), $('.price-range-max')) == true) {
   $(ids +' .price-range-min,'+ ids+ ' .price-range-max').css('opacity', '0'); 
   $(ids +' .price-range-both').css('display', 'block');  
  } else {
   $(ids +' .price-range-min,'+ ids+ ' .price-range-max').css('opacity', '1'); 
   $(ids +' .price-range-both').css('display', 'none');  
  }
  
 }
});

$(ids +' .ui-slider-range').append('<span class="price-range-both value"><i>' + $(ids).slider('values', 0 ) + ' - </i>' + $(ids).slider('values', 1 ) + '</span>');

$(ids +' .ui-slider-handle:eq(0)').append('<span class="price-range-min value">' + $(ids).slider('values', 0 ) + '</span>');

$(ids +' .ui-slider-handle:eq(1)').append('<span class="price-range-max value">' + $(ids).slider('values', 1 ) + '</span>');
}
<br>
 <input type="textbox" id="id1-min">
 <input type="textbox" id="id1-max">
 <p>&nbsp;</p>
 <div id="id1-range"></div>
<p>&nbsp;</p>
 <input type="textbox" id="id2-min">
 <input type="textbox" id="id2-max">
 <p>&nbsp;</p>
 <div id="id2-range" data-max="800"></div>
<p>&nbsp;</p>
 <input type="textbox" id="id3-min">
 <input type="textbox" id="id3-max">
 <p>&nbsp;</p>
 <div id="id3-range" data-max="800"></div>
 <p>&nbsp;</p>
 <input type="textbox" id="id4-min">
 <input type="textbox" id="id4-max">
 <p>&nbsp;</p>
 <div id="id4-range" data-max="800"></div>

2

There are 2 best solutions below

1
On

The reason of such behavior is in var keyword. When you assign variable ids in a for loop via var keyword it doesn't mean you create i amount of ids. No, sir. Actually you create one variable ids, which you reassign later in every iteration of your loop. This calls variable hoisting (and here is another article about it).

Your console.log shows value of ids variable on each iteration. But it doesn't mean that the slider handler references to different values of ids. No again. In this piece of code: $(ids + ' .ui-slider-handle:eq(0) .price-range-min') - ids references to one certain variable (one certain cell in RAM), which after all loop iterations contains '#id4-range' string. So you will always update the last slider.

You may ask: "why then all sliders created and not only the last one?". Thats because sliders are creating just once in each iteration. You set listeners on specific node and after that they will always be attached to that node.

So, how then you obtain needed behavior? One way is to simply use let keyword instead of var when declaring ids. This is ES6 (you better read a lot about it, it's super handy), so you may encounter with browser incompatibility (babel will help you with this). Another (wrong, see comment below) way is to save full selector string paths in one array variable, or simply keep using already existing search_type like so:

$('#' + search_type[i] + '-range .ui-slider-handle:eq(0) .price-range-min').html(ui.values[0]);

Here is your example with a little modification (let instead var before ids)

EDIT:

If you want to deal with it without using let you should create function createSlider, for example. Which will do the following:

function createSlider(rawId){
    var id = '#' + rawId + '-range';
    console.log(id);
    $(id).slider({
        range: true,
        min: 0,
        max: 500,
        values: [75, 300],
        slide: function(event, ui) {

            $(id + ' .ui-slider-handle:eq(0) .price-range-min').html(ui.values[0]);
            $(id + ' .ui-slider-handle:eq(1) .price-range-max').html(ui.values[1]);    

    // and so on...

} 

Simply call this function in every iteration of the loop and pass search_type[i] as an argument like so:

for (let i = 0; i < search_type.length; i++) {
    createSlider(search_type[i]);
}
1
On

Here is my concise version

<div id="id-slider1"></div>
<div id="id-slider2"></div>
<div id="id-slider3"></div>

$(document).ready(function() {
   $("[id^=id]").each(function(indx, element) {
       var id_range = $(this).attr('id');
                
       $('#'+id_range).slider({
         range: "min",    
         value: 50,
         slide: function( event, ui ) {
            //my custom code
            $('#line-'+indx).outerWidth( ui.value + "%" );
         }
       });
   });
});