53

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.

Rohan Kumar
  • 40,431
  • 11
  • 76
  • 106
Marty Wallace
  • 34,046
  • 53
  • 137
  • 200
  • Are any events bound directly to the list elements themselves? If not you could possibly just use `$('.listitems').html(function(){ return this.innerHTML; });` – David Thomas Feb 06 '14 at 10:57
  • There is just this question on the internals of sort() going http://stackoverflow.com/questions/21598566/explain-why-array-sort-act-this-way – loveNoHate Feb 06 '14 at 10:58

5 Answers5

131

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>
SwissCodeMen
  • 4,222
  • 8
  • 24
  • 34
Rohan Kumar
  • 40,431
  • 11
  • 76
  • 106
13

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

Ian
  • 184
  • 1
  • 3
5

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>
gaetanoM
  • 41,594
  • 6
  • 42
  • 61
0

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>
0

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

Udara Kasun
  • 2,182
  • 18
  • 25