4

I am a bit lost with trying to order an ul list by the span in the li.
This is my html code:

<ul id="appsList">
    <li><span>aa</span>  <span class="sort">android</span></li>
    <li><span>aa</span>  <span class="sort">ios</span></li>
    <li><span>aa</span>  <span class="sort">facebook</span></li>
    <li><span>bb</span>  <span class="sort">android</span></li>
    <li><span>bb</span>  <span class="sort">ios</span></li>
    <li><span>bb</span>  <span class="sort">facebook</span></li>
</ul>

I have an array that holds the platform names and doesn't have to contain all the platforms and the order of the platforms in the array doesn't matter. I would like the list to be sorted by alphabet order and after that by the alphabetic order of the first span.

So if my array is ["ios","android","facebook"] I would like to order by the elements in the array alphabetically and also by their first span value. So after sorting of the array we will get this:

<ul id="appsList">
    <li><span>aa</span>  <span class="sort">android</span></li>
    <li><span>bb</span>  <span class="sort">android</span></li>
    <li><span>aa</span>  <span class="sort">facebook</span></li>
    <li><span>bb</span>  <span class="sort">facebook</span></li>
    <li><span>aa</span>  <span class="sort">ios</span></li>
    <li><span>bb</span>  <span class="sort">ios</span></li>
</ul>

If the array is just ["ios"] then sort by alphabetically by the array elements and then the rest of the list by alphabet also:

<ul id="appsList">
    <li><span>aa</span>  <span class="sort">ios</span></li>
    <li><span>bb</span>  <span class="sort">ios</span></li>
    <li><span>aa</span>  <span class="sort">android</span></li>
    <li><span>bb</span>  <span class="sort">android</span></li>
    <li><span>aa</span>  <span class="sort">facebook</span></li>
    <li><span>bb</span>  <span class="sort">facebook</span></li>
</ul>

If the array is ["ios","android"] then "android" will be before "ios" and after that "facebook", because "facebook" is not in the array:

<ul id="appsList">
   <li><span>aa</span>  <span class="sort">android</span></li>
   <li><span>bb</span>  <span class="sort">android</span></li>
   <li><span>aa</span>  <span class="sort">ios</span></li>
   <li><span>bb</span>  <span class="sort">ios</span></li>
   <li><span>aa</span>  <span class="sort">facebook</span></li>
   <li><span>bb</span>  <span class="sort">facebook</span></li>
</ul>

This is what I have done so far: PLNKER

If this can be done easily using Underscore I would prefer that. Thank you.

8
  • The examples are confusing. Can you explain the difference between the 2nd and 3rd examples? Commented Jul 7, 2016 at 13:53
  • What does the first span mean? In the initial example you have all aas and then bbs, but afterwords you have them interchangeably? Commented Jul 7, 2016 at 14:02
  • @VijayDev There is no difference in the logic it just another example to show what I meant. Whatever is in the array should be sorted by alphabet, if a platform is not there then put after the sorting. Commented Jul 7, 2016 at 14:12
  • 1
    If you want to change order of existing DOM elements (list items) in place, it is a bad idea. I strongly suggest you to use JS templates instead. Commented Jul 7, 2016 at 14:13
  • @nem035 The first sort is by the platforms that are in the array, after that by the platforms that are not in the array and an inside sorting for each platform by the first span value, so if i have 2 list elements with first span "a" and the second is "b" then "a" should be before "b". Commented Jul 7, 2016 at 14:14

5 Answers 5

1

You will need to do break up the tasks by filtering and sorting. And then merging the two results.

Plunker Demo

 var arr = ["ios"];
 var $li = $('#appsList li').clone();
 var mySort = function(a, b) {
        var objA = {
            "span": $(a).find('span').not('.sort').text(),
            "sort": $(a).find('.sort').text()
        }
        var objB = {
            "span": $(b).find('span').not('.sort').text(),
            "sort": $(b).find('.sort').text()
        }
        output = objA.sort.localeCompare(objB.sort);
        if (objA.sort === objB.sort) {
            output = objA.span.localeCompare(objB.span);
        }
        return output
    } // mySort
 // Filter for what's in your array
 var arrFilter = function(index, el) {
    return arr.indexOf($(el).find('.sort').text()) > -1;
 }

 // Filter for what's not in your array
 var notArrFilter = function(index, el) {
    return arr.indexOf($(el).find('.sort').text()) < 0;
 }
 var $arrLi = $li.filter(arrFilter);
 var $notArrLi = $li.filter(notArrFilter);
 $arrLi = $arrLi.sort(mySort);
 $notArrLi = $notArrLi.sort(mySort);
 var $newLi = [];
 $.merge($newLi, $arrLi);
 $.merge($newLi, $notArrLi);
 $('#resultAppsList').html($newLi);
Sign up to request clarification or add additional context in comments.

Comments

1

My proposal is:

Number.prototype.pad = function(size) {
  var s = String(this);
  while (s.length < (size || 2)) {s = "0" + s;}
  return s;
};

function doStuff(arr) {
  var listAllUniqueEle = $.unique($('#appsList li .sort').map(function(index, element) {
    return element.textContent;
  })).sort().toArray();

  listAllUniqueEle = $.unique(arr.sort().concat(listAllUniqueEle));

  var $li = $('#appsList li').clone().sort(function(a, b) {
    var firstValue =  listAllUniqueEle.indexOf(a.childNodes[2].textContent).pad(3) +
        a.textContent + a.textContent;
    var secondValue = listAllUniqueEle.indexOf(b.childNodes[2].textContent).pad(3) +
        b.textContent;
    return firstValue.localeCompare(secondValue);
  });
  $('#resultAppsList').empty().html($li)
}

$(function () {
  $('#btn1').on('click', function(e) {
    doStuff(["ios","android","facebook"]);
  });

  $('#btn2').on('click', function(e) {
    doStuff(["ios"]);
  });

  $('#btn3').on('click', function(e) {
    doStuff(["ios","android"]);
  });
});
<script src="https://code.jquery.com/jquery-1.12.1.min.js"></script>

<button id="btn1">["ios","android","facebook"]</button>
<button id="btn2">["ios"]</button>
<button id="btn3">["ios","android"]</button>
<br>Before sort :
<ul id="appsList">
    <li><span>bb</span> <span class="sort">ios</span></li>
    <li><span>bb</span> <span class="sort">facebook</span></li>
    <li><span>bb</span> <span class="sort">android</span></li>
    <li><span>aa</span> <span class="sort">ios</span></li>
    <li><span>aa</span> <span class="sort">facebook</span></li>
    <li><span>aa</span> <span class="sort">android</span></li>
    <li><span>aa</span> <span class="sort">android01</span></li>
    <li><span>bb</span> <span class="sort">android01</span></li>
    <li><span>aa</span> <span class="sort">android02</span></li>
    <li><span>bb</span> <span class="sort">android02</span></li>
    <li><span>aa</span> <span class="sort">android03</span></li>
    <li><span>bb</span> <span class="sort">android03</span></li>
    <li><span>aa</span> <span class="sort">android04</span></li>
    <li><span>bb</span> <span class="sort">android04</span></li>
    <li><span>aa</span> <span class="sort">android05</span></li>
    <li><span>bb</span> <span class="sort">android05</span></li>
    <li><span>aa</span> <span class="sort">android06</span></li>
    <li><span>bb</span> <span class="sort">android06</span></li>
    <li><span>aa</span> <span class="sort">android07</span></li>
    <li><span>bb</span> <span class="sort">android07</span></li>
    <li><span>aa</span> <span class="sort">android08</span></li>
    <li><span>bb</span> <span class="sort">android08</span></li>
    <li><span>aa</span> <span class="sort">android09</span></li>
    <li><span>bb</span> <span class="sort">android09</span></li>
    <li><span>aa</span> <span class="sort">android10</span></li>
    <li><span>bb</span> <span class="sort">android10</span></li>
    <li><span>aa</span> <span class="sort">android11</span></li>
    <li><span>bb</span> <span class="sort">android11</span></li>
    <li><span>aa</span> <span class="sort">android12</span></li>
    <li><span>bb</span> <span class="sort">android12</span></li>
    <li><span>aa</span> <span class="sort">android13</span></li>
    <li><span>bb</span> <span class="sort">android13</span></li>
    <li><span>aa</span> <span class="sort">android14</span></li>
    <li><span>bb</span> <span class="sort">android14</span></li>
    <li><span>aa</span> <span class="sort">android15</span></li>
    <li><span>bb</span> <span class="sort">android15</span></li>
    <li><span>aa</span> <span class="sort">android16</span></li>
    <li><span>bb</span> <span class="sort">android16</span></li>
    <li><span>aa</span> <span class="sort">android17</span></li>
    <li><span>bb</span> <span class="sort">android17</span></li>
    <li><span>aa</span> <span class="sort">android18</span></li>
    <li><span>bb</span> <span class="sort">android18</span></li>
    <li><span>aa</span> <span class="sort">android19</span></li>
    <li><span>bb</span> <span class="sort">android19</span></li>
    <li><span>aa</span> <span class="sort">android20</span></li>
    <li><span>bb</span> <span class="sort">android20</span></li>
</ul>

After sort :
<ul id="resultAppsList">
</ul>

2 Comments

It didn't work for me in large scales, when there are 18 <li> elements it gets mixed...
@OffirPe'er Sorry for my mistake. Now it works. Let me know.
0

EDIT: this only does the first sort, you'll have to modify sortElements to group them by .sort then do another pass on li span:first-child.

I use roughly this to sort a list by data-* attributes, here's the code modified for your use. Get the array of elements with jquery then use javascript's native sort to order them. This will sort them alphabetically. In my use case, each element is assigned a data-* attribute with a numerical value (that code is below the first example). Here's a jsfiddle.

function sortElements($parent, selector, sortSelector) {
    var elArr = $parent.find(selector).get();

    var sorted = elArr.sort(function (a, b) {
        var aSortOrder = $(a).find(sortSelector).text();
        var bSortOrder = $(b).find(sortSelector).text();

        if (aSortOrder > bSortOrder)
            return 1;
        else if (aSortOrder < bSortOrder)
            return -1;
        else
            return 0;
    });

    $parent.html(sorted);
}

Sorting by numerical data-* attributes:

function sortElements($parent, selector, dataAttr) {
    var elArr = $parent.find(selector).get();

    var sorted = elArr.sort(function (a, b) {
        var aSortOrder = parseInt($(a).data(dataAttr), 10);
        var bSortOrder = parseInt($(b).data(dataAttr), 10);

        if (aSortOrder > bSortOrder)
            return 1;
        else if (aSortOrder < bSortOrder)
            return -1;
        else
            return 0;
    });

    $parent.html(sorted);
}

Comments

0

I have found a solution: this is my js code

function listElementsWithMyArray(){

    //here you can configure your array
    var myArray = ["ios"];

    //creates all needed variables
    var elements = document.getElementsByClassName("sort");
    var ulelement = document.getElementById("myUL");
    var elementStrings = [];
    var elementStringsInMyArray = [];
    var elementStringsNotInMyArray = [];

    //to fill the list with the values of the spans
    for(var i = 0; i < elements.length; i++){
        var element = elements[i];
        elementStrings.push(element.innerHTML);
    }

    //sort the list and also remove the <li> items
    elementStrings.sort();
    ulelement.innerHTML = "";

    //check if the item is in your array and add to the final arrays
    for(var i = 0; i < elementStrings.length; i++){
        var b = 0;
        if(myArray.indexOf(elementStrings[i]) > -1){
            elementStringsInMyArray.push(elementStrings[i]);
            b = 1;
        }else{
            elementStringsNotInMyArray.push(elementStrings[i]);
        }
    }

    //sort both arrays
    elementStringsInMyArray.sort();
    elementStringsNotInMyArray.sort();

    //list all items from myArray and later on from notMyArray
    for(var i = 0; i < elementStringsInMyArray.length; i++){
        ulelement.innerHTML = ulelement.innerHTML + '<li><span class="sort">' + elementStringsInMyArray[i] + '</class></li>';
    }
    for(var i = 0; i < elementStringsNotInMyArray.length; i++){
        ulelement.innerHTML = ulelement.innerHTML + '<li><span class="sort">' + elementStringsNotInMyArray[i] + '</class></li>';
    }

}

and this is my html code

<ul id="myUL">
    <li><span class="sort">android</span>
    <li><span class="sort">facebook</span>
    <li><span class="sort">ios</span>
    <li><span class="sort">android</span>
    <li><span class="sort">facebook</span>
    <li><span class="sort">ios</span>
</ul>

I know you would have liked the code in jQuery but I saw it just when I finished - if you like my code and you'd like me to rewrite it in jQuery I'm fine with that ^^

elsewhise I hope it helps ;)

1 Comment

It says JQuery in the title , but I do appreciate your help.
0

I think this is what you are after. It produces a sort based first on the inclusion in the array, then on the .sort span and finally on the initial span. The results are appended back to the original parent container appearing to be an in-place sort. This example starts with your "unsorted" list from your code.

A lot of this is code is just comments that you can of course strip out.

// --------------------------
// items in this array will sort ahead of those not in the array
// note: position in the array is not important
// --------------------------
var arr = ["ios"];
// --------------------------

// --------------------------
// the parent container
// used to find children and for re-inserting children in the correct order
// --------------------------
var parent = document.getElementById("appsList");
// --------------------------

// --------------------------
// children to be sorted
// --------------------------
var items = Array.from(parent.querySelectorAll("li"));
// --------------------------

// --------------------------
// sort the children
// --------------------------
items.sort(function(a,b){
  // --------------------------
  // create a string that will be sorted
  // --------------------------
  var _prep = function(item){
    var text1 = item.querySelector("span").innerText;
    var text2 = item.querySelector(".sort").innerText;
    return (arr.indexOf(text2) != -1 ? "a~" : "z~") + text2 + "~" + text1
  };
  // --------------------------

  // --------------------------
  // traditional alpha sort function
  // --------------------------
  var _sortAlpha = function(a, b){
    if( a < b ) return -1;
    if( a > b) return 1;
    return 0;
  };
  // --------------------------
  
  // --------------------------
  // return the alpha sorting of our special strings
  // --------------------------
  return _sortAlpha(_prep(a), _prep(b));
  // --------------------------
});
// --------------------------

// --------------------------
// re-insert the children back into the parent
// effectively an in-place sorting
// --------------------------
items.forEach(function(item){ parent.appendChild(item); });
// --------------------------
<ul id="appsList">
    <li><span>bb</span> <span class="sort">ios</span></li>
    <li><span>bb</span> <span class="sort">facebook</span></li>
    <li><span>bb</span> <span class="sort">android</span></li>
    <li><span>aa</span> <span class="sort">ios</span></li>
    <li><span>aa</span> <span class="sort">facebook</span></li>
    <li><span>aa</span> <span class="sort">android</span></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.