1

In this sort function I want to be able to re-arrange each .item based on the nested [data-sort] value when the corresponding [data-head] value is clicked.

The problem with the current code is that it creates a new list and sorts the results instead of just re-arranging each .item to match the sort criteria.

How do I set up the sort function to re-arrange each .item based on the data-sort values that match the data-head value?

$(".table").on("click", ".btn", function() {
  let table = $(this).closest(".table").eq(0);
  let rows = table
    .find("[data-sort]")
    .toArray()
    .sort(comparer($(this).index()));
  this.asc = !this.asc;
  if (!this.asc) {
    rows = rows.reverse();
  }
  for (var i = 0; i < rows.length; i++) {
    table.append(rows[i]);
  }
});

function comparer(index) {
  return function(a, b) {
    var valA = getCellValue(a, index),
      valB = getCellValue(b, index);
    return $.isNumeric(valA) && $.isNumeric(valB) ?
      valA - valB :
      valA.localeCompare(valB);
  };
}

function getCellValue(row, index) {
  return $(row).find("[data-sort]").eq(index).text();
}
.list {
  display: flex;
  flex-direction: column;
}

.item,
.header {
  display: flex;
}

.btn {
  cursor: pointer;
}

[data-sort] {
  border: 1px solid;
  padding: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="table">
  <div class="header">
    <div class="btn" data-head='country'>Country</div>
    <div class="btn" data-head='price'>Price</div>
  </div>
  <div>
    <div class="list">
      <div class="item">
        <div data-sort="country">France</div>
        <div>Content</div>
        <div>Content</div>
        <div data-sort="price">$25</div>
      </div>
      <div class="item">
        <div data-sort="country">spain</div>
        <div>Content</div>
        <div>Content</div>
        <div data-sort="price">$25</div>
      </div>
      <div class="item">
        <div data-sort="country">Lebanon</div>
        <div>Content</div>
        <div>Content</div>
        <div data-sort="price">$17</div>
      </div>
    </div>
  </div>
</div>

4
  • you want to sort an keep the same view , not create a new html view? Commented Feb 16, 2021 at 16:16
  • Yes just rearrange the items and do not change the HTML markup Commented Feb 16, 2021 at 16:17
  • what do you do with <div>Content</div>? they dont appear in the sort and result final Commented Feb 16, 2021 at 16:34
  • It's just to show that the data-sort content are not related and could be nested anywhere within each .item Commented Feb 16, 2021 at 16:35

1 Answer 1

1

I have rewritten your code for the sort :

var keys = [...$(".table .btn")].map((i) => $(i).text());
var arr = [...$(".list .item")].map((i) => {
                         var data = $(i).find("[data-sort]");
                         var obj = {};
                         for(let id=0; id < data.length;id++){
                            obj[keys[id]]=data.eq(id).text();
                            obj.line = $(i)[0].outerHTML;
                         }
                         return obj;
                      }); 
        
//console.log("arr",  arr);        
                      
var lastkey = -1;
$(".table .btn").on("click", function() {
  var keytosort = keys[Number($(".table .btn").index(this))];
  var desc = true; 
  if(keytosort == lastkey){
    desc = true;lastkey = -1;
  }else{
    desc = false;lastkey=keytosort;
  }
  
  
  arr = arr.sort((a, b) => {
    if(a[keytosort].startsWith("$")){  
     let an = a[keytosort].substring(1); //put off $
     let bn = b[keytosort].substring(1);
     return Number(an) - Number(bn);
    } else{
     return a[keytosort].localeCompare(b[keytosort]); 
    }
  });//end sort
  
  if(desc)arr = arr.reverse();
  
  //recreate the different items
  $(".list").children().remove();

  for(let i = 0;i < arr.length ; i++){
    $(".list").append(arr[i].line);
  }
});
.list {
  display: flex;
  flex-direction: column;
}

.item,
.header {
  display: flex;
}

.btn {
  cursor: pointer;
}

[data-sort] {
  border: 1px solid;
  padding: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="table">
  <div class="header">
    <div class="btn" data-head='country'>Country</div>
    <div class="btn" data-head='price'>Price</div>
  </div>
  <div>
    <div class="list">
      <div class="item">
        <div data-sort="country">France</div>
        <div>Contentf1</div>
        <div>Contentf2</div>
        <div data-sort="price">$25</div>
      </div>
      <div class="item">
        <div data-sort="country">spain</div>
        <div>Contents1</div>
        <div>Contents2</div>
        <div data-sort="price">$30</div>
      </div>
      <div class="item">
        <div data-sort="country">Lebanon</div>
        <div>Contentsss</div>
        <div>Contentszz</div>
        <div data-sort="price">$17</div>
      </div>
    </div>
  </div>
</div>

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

6 Comments

Thanks @Frenchy. Is there a way to toggle the sort by clicking again? Currently it only sorts one way
If you sort country then price then country...I don't see problem...
I want to be able to sort price highest to lowest and name from A-Z or Z-A. Any data I have to sort I will need to go either way with it
ok i understand, so the sort is descending when you reclick on same key, and so on
The actually .item is supposed to re-arrange not just the content within the item. Each item is a separate entry and I want to re-arrange them based on the sort selection.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.