Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting list of elements in JQuery

I have a list of elements that I get using JQuery.

var $self = $(this);
var $fields = $('.identifier-controls', $self);

This list is the list of elements that need to be manipulated in some way when the control renders. Each element in the list of $fields contains a data attribute called "data-order". This attribute tells me what order I should arrange the elements with in the control (ah requirements). The order does not have to be in direct linear order (meaning that the first control can have an attribute value of 10 and the next one 15 and the next one 17 etc. They just need to appear in the asc order. Is there a simple way to achieve this? All the ways that I can come up with seem a bit over complicated.

like image 390
The Sheek Geek Avatar asked Dec 08 '11 15:12

The Sheek Geek


4 Answers

Steps to sort jquery "array-like" objects by data attribute...

  1. select all object via jquery selector
  2. convert to actual array (not array-like jquery object)
  3. sort the array of objects
  4. convert back to jquery object with the array of dom objects

Html

<div class="item" data-order="2">2</div>
<div class="item" data-order="1">1</div>
<div class="item" data-order="4">4</div>
<div class="item" data-order="3">3</div>

Plain jquery selector

$('.item');
[<div class="item" data-order="2">2</div>,
 <div class="item" data-order="1">1</div>,
 <div class="item" data-order="4">4</div>,
 <div class="item" data-order="3">3</div>
]

Lets sort this by data-order

function getSorted(selector, attrName) {
    return $($(selector).toArray().sort(function(a, b){
        var aVal = parseInt(a.getAttribute(attrName)),
            bVal = parseInt(b.getAttribute(attrName));
        return aVal - bVal;
    }));
}
> getSorted('.item', 'data-order')
[<div class="item" data-order="1">1</div>,
 <div class="item" data-order="2">2</div>,
 <div class="item" data-order="3">3</div>,
 <div class="item" data-order="4">4</div>
]

See how getSorted() works.

Hope this helps!

like image 195
Troy Grosfield Avatar answered Oct 31 '22 13:10

Troy Grosfield


An insertion sort would be a fairly straight-forward way of doing it.

Or being a bit subversive, you can take advantage of the JavaScript engine for this:

var $fields, $container, sorted, index;

$container = $('body');
$fields = $("div[data-order]", $container);
sorted = [];
$fields.detach().each(function() {
    sorted[parseInt(this.getAttribute("data-order"), 10)] = this;
});
sorted.forEach(function(element) {
    $container.append(element);
});

Live Example:

(function($) {
    var $fields, $container, sorted, index;
  
    $container = $('body');
    $fields = $("div[data-order]", $container);
    sorted = [];
    $fields.detach().each(function() {
        sorted[parseInt(this.getAttribute("data-order"), 10)] = this;
    });
    sorted.forEach(function(element) {
        $container.append(element);
    });
})(jQuery);
<div data-order="30">30</div>
<div data-order="40">40</div>
<div data-order="10">10</div>
<div data-order="20">20</div>
<div data-order="1">1</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Here's how that works:

  • We get the container, and get the fields from it.

  • We create a blank array. Remember that JavaScript arrays aren't really arrays at all, and they're inherently sparse.

  • We detach the fields, then loop through them, getting the data-order from the DOM element and adding the DOM element to the array in that position. This assumes that data-order values are unique.

  • Once we have the array of raw DOM elements, we loop through it using forEach, appending them to the container. I didn't use jQuery.each because jQuery.each will call the callback even for non-existant array indexes, which if your data-order values are quite sparse could be a problem. forEach iterates the entries in numeric order, skipping over ones that don't exist.

like image 45
T.J. Crowder Avatar answered Sep 27 '22 23:09

T.J. Crowder


Try this:

$(function(){
   var $self = $(this);
   var sortedList = $('.identifier-controls', $self).sort(function(lhs, rhs){
      return parseInt($(lhs).attr("data-order"),10) - parseInt($(rhs).attr("data-order"),10);
   });
});

the variable sortedList now has the sorted elements.

like image 8
epignosisx Avatar answered Oct 31 '22 13:10

epignosisx


Something like:

$fields.sort(function(a, b) {
    return a.getAttribute('data-order') > b.getAttribute('data-order');
}).appendTo($fields.parent());

Fiddle: http://jsfiddle.net/gCFzc/

like image 6
David Hellsing Avatar answered Oct 31 '22 15:10

David Hellsing