jquery sort list based on data attribute value

Jquery

Jquery Problem Overview


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.

Jquery Solutions


Solution 1 - Jquery

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>

Solution 2 - Jquery

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

Solution 3 - Jquery

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>

Solution 4 - Jquery

What about using sort and replace inside DOM

function sortLiElements(a,b) {
	return parseInt($(a).data('position')) -   parseInt($(b).data('position'));
}

$('.listitems').html($('.listitems li').sort(sortLiElements));

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.2/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>

Solution 5 - Jquery

Try this

function sortList() {
  var list, i, switching, b, shouldSwitch;
  list = document.getElementById("id01");
  switching = true;
  /* Make a loop that will continue until
  no switching has been done: */
  while (switching) {
     
    // start by saying: no switching is done:
    switching = false;
    b = list.getElementsByTagName("LI");
    // Loop through all list-items:
    for (i = 0; i < (b.length - 1); i++) {
      // start by saying there should be no switching:
      shouldSwitch = false;
      /* check if the next item should
      switch place with the current item: */
     //alert(b[i].getAttribute("order"));
      if (b[i].getAttribute("order").toLowerCase() > b[i + 1].getAttribute("order").toLowerCase()) {
        /* if next item is alphabetically
        lower than current item, mark as a switch
        and break the loop: */
        shouldSwitch = true;
        break;
      }
    }
    if (shouldSwitch) {
      /* If a switch has been marked, make the switch
      and mark the switch as done: */
      b[i].parentNode.insertBefore(b[i + 1], b[i]);
      switching = true;       
    }
  }
}

 <button onclick="sortList()">Sort List</button>
 
 <ul id="id01">
    <li order="A" class="disname disheader">Pending</li>
    <li order="AA" class="disname">302-1 Energy Consumption</li>
    <li order="AA" class="disname">302-3 Energy Intensity</li>
    <li order="DD" class="disname">EN-31 Environmental Expenditure/Investment</li>
    <li order="DD" class="disname">103-2  Environmental Grievances</li>
    <li order="D" class="disname disheader">Deactive</li>                               
    <li order="BB" class="disname">305-4  Emission Intensity</li>                             
    <li order="BB" class="disname">306-2 Total Waste</li>
    <li order="BB" class="disname">307-1 Compliance</li>
    <li order="AA" class="disname">302-4 Energy/Electricity Reduction Initiative</li>
    <li order="AA" class="disname">303-1 Water Withdrawal by Source</li>
    <li order="AA" class="disname">303-3 Recycled Water</li>
    <li order="C" class="disname disheader">Auto Generated</li>
    <li order="CC" class="disname">305-1 GHG Emission</li>
    <li order="CC" class="disname">305-2 GHG Emission</li>
    <li order="CC" class="disname">305-3 GHG Emission</li>
    <li order="BB" class="disname">05-5 Reduction of GHG Emissions</li>
    <li order="BB" class="disname">306-1 Water Discharge</li>  
    <li order="B" class="disname disheader">Overdue</li>                              
</ul>

Codepen Example

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMarty WallaceView Question on Stackoverflow
Solution 1 - JqueryRohan KumarView Answer on Stackoverflow
Solution 2 - JqueryIanView Answer on Stackoverflow
Solution 3 - JquerygaetanoMView Answer on Stackoverflow
Solution 4 - JquerySunil GoyalView Answer on Stackoverflow
Solution 5 - JqueryUdara KasunView Answer on Stackoverflow