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

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.