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.

2
  • Are any events bound directly to the list elements themselves? If not you could possibly just use $('.listitems').html(function(){ return this.innerHTML; }); Commented Feb 6, 2014 at 10:57
  • There is just this question on the internals of sort() going stackoverflow.com/questions/21598566/… Commented Feb 6, 2014 at 10:58

5 Answers 5

132

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>

Sign up to request clarification or add additional context in comments.

7 Comments

Does appendTo() replace the elements?
Yes, you can say. For testing you can check your console by using console.log($(".listitems li").sort(sort_li)); which will give you the sorted list. No doubt here, $('.listitems').html($(".listitems li").sort(sort_li)); will give you the same result as expected.
appendTo() is to MOVE element into specific container element in last position. jQuery documentation explained it all. :)
Item I not coming on top
Add data-position to all li elements(see kalu and gudiya), otherwise it breaks the sort logic.
|
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

1 Comment

this is beautifuly made 👌 you just saved my day
6

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>

Comments

1

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

Comments

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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.