Search code examples
javascriptjquery

How to display a selection of DOM elements in order in JQ?


Please tell me, I can’t understand what’s wrong.

Task: There is a set of house elements (can be anything). I hide all elements, take a set of elements from the DOM by class, randomly select, for example, 5 elements, add them to an empty array and want to output them only from the array by iterating over each one, but in order. As a result, the numbering is displayed inconsistently... What's the matter? Is it enumerating out of order?

$(document).ready(function () {

var elems = $(".test");
var items_ = [];
    
    for (var i = 0; (i < 5) && (i < elems.length); i++) {
    var r = Math.floor(Math.random() * (elems.length - i)) + i;
    var res = elems[r];
    elems[r] = elems[i];
    elems[i] = res;
    items_.push(res)
    }
        $('.test').fadeOut('slow', function(){
          $(items_).each(function (index) {
          $(this).find('.number_test').text(index + 1);
          $(this).fadeIn('slow')
          });
        })  
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div class="test">First - <span class="number_test"></span></div>
<div class="test">Second - <span class="number_test"></span></div>
<div class="test">Third - <span class="number_test"></span></div>
<div class="test">Fourth - <span class="number_test"></span></div>
<div class="test">Fifth - <span class="number_test"></span></div>
<div class="test">Sixth - <span class="number_test"></span></div>
<div class="test">Seventh - <span class="number_test"></span></div>
<div class="test">Eighth - <span class="number_test"></span></div>
<div class="test">Ninth - <span class="number_test"></span></div>
<div class="test">Tenth - <span class="number_test"></span></div>


Solution

  • The order of the elements in your items_ array is different from the order these elements have in the DOM. This explains why the first element in the array might not be the topmost element (in their visual order) among those that are in the array.

    If you want the order in the array to also be the visual order of these elements, then you really need to move those elements in the DOM.

    You can do that move by simply adding those selected elements again (in the order they are put in the array) to their parent container element:

        $('.test').parent().append(items_);
    

    Add this statement in the callback function that runs after the fade out, and it will work. Be aware though that now the order of the elements has really changed, so that if you would unhide also the other elements, you will not see the original order.

    Other remark

    The each loop is executed (as a whole) multiple times, because the fadeOut callback is executed for every element that matches the .test selector. This is obviously overkill: you only need that fadeOut callback to execute once. You can do that by getting the promise and chain a then call to it:

        $('.test').fadeOut('slow').promise().then(function(){
            $('.test').parent().append(items_);
            $(items_).each(function (index) {
                $(this).find('.number_test').text(index + 1);
                $(this).fadeIn('slow');
            });
        });