0

I use the following script, to have multiple jQuery UI sliders with a combined total: Combined total for multiple jQuery-UI Sliders

Now I want to start with one slider on page load, and after a button click I want to add another slider that should be included in the calculation. But unfortunately with my approach, when I add a new slider, the first slider gets the value NaN and when I try to move it, I get the following error Uncaught TypeError: Cannot read property 'addClass' of undefined.

When I include multiple sliders from the beginning (via PHP), it works without problems.

Here is the html structure:

<div class="form-group taskType">
     <label for="TaskType32" class="col-sm-4 control-label">Aufgaben Art</label>
           <div class="col-sm-8">
              <select class="form-control" id="TaskType32" name="type[]">
                  <optgroup label="DESIGN">
                      <option value="photoshop">PHOTOSHOP</option>
                      <option value="recherche">RECHERCHE</option>
                   </optgroup>
             </select>
             <div class="rangeSliderContainer">
                 <div class="slider">100</div>
                 <span class="value">100</span>%
             </div>
             <input type="hidden" class="hiddenPercentage" name="percentage[]" value="100">
        </div>
</div>

Here is my approach:

1.) I clone the element first

clonedTaskAdd = $('.createfinishedTask .taskType').clone();

2.) Then I initialize the slider function

manageSliders();

function manageSliders() {
    var sliders = $(".rangeSliderContainer .slider");
    var availableTotal = 100;

    sliders.each(function() {
        var init_value = parseInt($(this).text());

        $(this).siblings('.value').text(init_value);

        $(this).empty().slider({
            value: init_value,
            min: 0,
            max: availableTotal,
            range: "max",
            step: 2,
            animate: 0,
            slide: function(event, ui) {

                // Update display to current value
                $(this).siblings('.value').text(ui.value);
                $(this).parent().next('.hiddenPercentage').val(ui.value);

                // Get current total
                var total = 0;

                sliders.not(this).each(function() {
                    total += $(this).slider("option", "value");
                });

                // Need to do this because apparently jQ UI
                // does not update value until this event completes
                total += ui.value;

                var delta = availableTotal - total;

                // Update each slider
                sliders.not(this).each(function() {
                    var t = $(this),
                        value = t.slider("option", "value");

                    var new_value = value + (delta/2);

                    if (new_value < 0 || ui.value == 100)
                        new_value = 0;
                    if (new_value > 100)
                        new_value = 100;

                    t.siblings('.value').text(new_value);
                    t.slider('value', new_value);
                    t.parent().next('.hiddenPercentage').val(new_value);
                });
            }
        });
    });
}

3.) On the button click, I change the values of the clone and append it

$('.createfinishedTask').on('click', '.rangeTrigger', function(e) {
        e.preventDefault();
        addSlider();
    });


function addSlider() {
    clonedTaskAdd.find('.slider, .value').text('0');
    clonedTaskAdd.find('.hiddenPercentage').val('0');
    clonedTaskAdd.find('.slider').slider();
    $('.createfinishedTask .taskType').last().after(clonedTaskAdd);
    manageSliders();
}

So the problem occurs after I call the last manageSliders(); inside the addSlider() function. But I don't know how to include the new added slider into the total calculation.

FIDDLE

Feel free to ask if you need more information. Thank you!

Community
  • 1
  • 1
Sebsemillia
  • 9,366
  • 2
  • 55
  • 70
  • An initial observation is that you are cloning elements with IDs (e.g. `id="TaskType32"`). IDs must be unique on a page (jQuery will only find the first one). You need to rework the HTML you are cloning to suit this rule. – iCollect.it Ltd Sep 03 '14 at 21:10
  • @TrueBlueAussie Thank you for your answer, but this isn't the problem. Even when I remove the ID, the problem persists. – Sebsemillia Sep 03 '14 at 21:13
  • That was only an observation, not intended to answer the main problem. With so much code, and potential for multiple issues, you really should put it all in a JSFiddle :) – iCollect.it Ltd Sep 03 '14 at 21:22
  • Q: Are you cloning the clone for each copy? Otherwise you wind up moving the original cloned element around on subsequent `after` calls. – iCollect.it Ltd Sep 03 '14 at 21:25
  • No, I'm not cloning it for each copy. I just clone it once on document ready. And the problem already starts with the first dynamically added element. Yes, I know that it is hard to find something with so much code, I just thought maybe it's something obvious I'm missing. I haven't got much time now, I'll try to create a fiddle tomorrow. Thank you for your efforts! – Sebsemillia Sep 03 '14 at 21:55
  • I added a Fiddle with the problem ^^ – Sebsemillia Sep 03 '14 at 22:04
  • Thanks. A Fiddle makes it easy for something this complicated (pretty cool what your code does by the way). Solution below. – iCollect.it Ltd Sep 04 '14 at 08:19
  • No problem. Normally I add a working fiddle to all my questions, but I thought maybe it's something obvious (and the amount of code deterred me this time). Thank you, I'm flattered that you like my code :) – Sebsemillia Sep 04 '14 at 12:34

1 Answers1

1

The problem is the code that initialises the sliders. You extract a text value from the existing slider, but the DOM has changed for that slider so you get a NAN value.

The main change I made was this: http://jsfiddle.net/TrueBlueAussie/p5ty5wbv/3/

    // This value comes from the text element, but only if not converted to a slider
    if ($this.find('.ui-slider-handle').length) {
        var init_value = $this.slider("option", "value");
    } else {
        var init_value = ~~$this.text();
    }

I also changed the cloning to use a clone of the clone so problems with reusing the element go away:

function addSlider() {
    var clone = clonedTaskAdd.clone();
    clone.find('.slider, .value').text('0');
    // clonedTaskAdd.find('.slider').text('0');
    clone.find('.hiddenPercentage').val('0');
    var rand = makeid();
    clone.find('label').attr('for', rand);
    clone.find('select').attr('id', rand);
    clone.find('.slider').slider();
    $('.createfinishedTask .taskType').last().after(clone);
    // $('.createfinishedTask .taskType').last().find('.slider').slider();
    manageSliders();
}

other minor tweaks were where I started to add temp vars instead of re-jquerying elements and the use of ~~ instead of parseInt (faster and shorter integer truncation).

iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202
  • Thank you very much! Now it works, but unfortunately the updated calculations are wrong from time to time. Just play around with your fiddle, add some more sliders and move them randomly and look at the different numbers, sometimes they are over 100, sometimes below.. I accepted your answer nevertheless, since it answered my original question. But if you have time and space, feel free to look into it. You seem to have much more experience with JS as I do.. ;) Thanks again for your help and detailed answer. – Sebsemillia Sep 04 '14 at 12:31
  • Yep, looks like integer rounding problems. Can you explain what your algorithm is for apportioning the slider values when one changes? – iCollect.it Ltd Sep 04 '14 at 12:55
  • The rounding errors (`+/- n` where `n` is the number of sliders) occurs each time a slider is moved, so the error increases with use. You need to cap the values, but I need to understand your algorithm before I can suggest how :) – iCollect.it Ltd Sep 04 '14 at 13:21
  • It's within the `manageSliders()` function. As I said in my question, I got most of the code from this answer: http://stackoverflow.com/questions/3486371/combined-total-for-multiple-jquery-ui-sliders#answer-16381126 – Sebsemillia Sep 04 '14 at 13:22
  • Ah... so basically you don't know how it works either :) I will investigate when I get a chance to relax and think it through. Reverse engineering other peoples' javascript can be painful :> – iCollect.it Ltd Sep 04 '14 at 13:23
  • Yes, you are correct. :) Hehe, yeah I can imagine the pain, I already tried to understand it myself, but without much success yet. I'll let you know if I make progress. Thank you very much! – Sebsemillia Sep 04 '14 at 13:25
  • Well, reverse engineering made no sense, since the approach couldn't work at all on a closer look imho. I tried to write my own logic, but that made my brain hurt since it is a more complicated matter then I thought on the first look. I now went with this script, it seems to make the best job: http://keith-wood.name/linkedSliders.html . All other plugins I found proved buggy after some intense testing. Just wanted to let you know ;) – Sebsemillia Sep 05 '14 at 19:49