Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jquery sort list based on data attribute value

Tags:

jquery

Given the following list

<ul class="listitems">
    <li data-position="1">Item 1</li>
    <li data-position="2">Item 2</li>
    <li data-position="3">Item 3</li>
    <li data-position="4">Item 4</li>
</ul>

there is some functionality on the page that will allow the possibility of these items changing position. For example, they may get to the following state (example only, the order could be anything):

<ul class="listitems">
    <li data-position="3">Item 3</li>
    <li data-position="2">Item 2</li>
    <li data-position="1">Item 1</li>
    <li data-position="4">Item 4</li>
</ul>

I am looking for a small function to reset the order. So far I have the following:

function setPositions()
{
    $( '.listitems li' ).each(function() {
        var position = $(this).data('position');
        $(this).siblings().eq(position+1).after(this);
    });
}

But it isnt working correctly. What am i doing wrong?

An additonal condition is that the order of the list might not have changed, and so the function has to work in that scenario also.

like image 253
Marty Wallace Avatar asked Feb 06 '14 10:02

Marty Wallace


3 Answers

Try to use sort() with appendTo(),

$(".listitems li").sort(sort_li) // sort elements
                  .appendTo('.listitems'); // append again to the list
// sort function callback
function sort_li(a, b){
    return ($(b).data('position')) < ($(a).data('position')) ? 1 : -1;    
}

Snippet:

$(function() {
  $(".listitems li").sort(sort_li).appendTo('.listitems');
  function sort_li(a, b) {
    return ($(b).data('position')) < ($(a).data('position')) ? 1 : -1;
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<ul class="listitems">
  <li data-position="3">Item 3</li>
  <li data-position="2">Item 2</li>
  <li data-position="1">Item 1</li>
  <li data-position="4">Item 4</li>
</ul>
like image 138
Rohan Kumar Avatar answered Oct 24 '22 13:10

Rohan Kumar


Expanding on Rohan's answer, if you want this to work for multiple lists rather than just one, you can use the following:

HTML:

<ul class="listitems autosort">
    <li data-position="3">Item 3</li>
    <li data-position="2">Item 2</li>
    <li data-position="1">Item 1</li>
    <li data-position="4">Item 4</li>
</ul>

<ul class="listitems autosort">
    <li data-position="5">Item 5</li>
    <li data-position="6">Item 6</li>
    <li data-position="3">Item 3</li>
    <li data-position="4">Item 4</li>
</ul>

Javascript:

$(".listitems.autosort").each(function(){
    $(this).html($(this).children('li').sort(function(a, b){
        return ($(b).data('position')) < ($(a).data('position')) ? 1 : -1;
    }));
});

That will allow you to add as many lists as you like and sort them all by just setting the class autosort.

Live Example

like image 29
Ian Avatar answered Oct 24 '22 11:10

Ian


My proposal, in full javascript, is:

document.addEventListener("DOMContentLoaded", function(e) {
  Array.prototype.slice.call(document.querySelectorAll('.listitems li')).sort(function(a, b) {
    return a.getAttribute('data-position').localeCompare(b.getAttribute('data-position'));
  }).forEach(function(currValue) {
    currValue.parentNode.appendChild(currValue);
  });
});
<ul class="listitems">
    <li data-position="3">Item 3</li>
    <li data-position="2">Item 2</li>
    <li data-position="1">Item 1</li>
    <li data-position="4">Item 4</li>
</ul>
like image 21
gaetanoM Avatar answered Oct 24 '22 13:10

gaetanoM