0

I have a problem.

.titel
{
 display: inline-block;
 padding:5px 0 ;
}

#sort div div
{
 display: inline-block;
 padding:5px 0 ;
}
  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
  <div>
   <div class="titel achternaam" >Achternaam</div>
   <div class="titel voornaam" >Voornaam</div>
   <div class="titel kantoor" >Kantoor</div>  
  </div>



  <div class="spann">
   <span class="ui-icon ui-icon-circle-triangle-n"></span>
   <span class="ui-icon ui-icon-circle-triangle-s"></span>
   <span class="ui-icon ui-icon-circle-triangle-n"></span>
   <span class="ui-icon ui-icon-circle-triangle-s"></span>
   <span class="ui-icon ui-icon-circle-triangle-n"></span>
   <span class="ui-icon ui-icon-circle-triangle-s"></span>
  </div>


  <div id="sort">   
   <div  class="someaspcode" onClick="someaspcodethatifyouclickitwilgotothepage">
          <div class="achternaam">bill</div>
          <div class="voornaam">gates</div>
          <div class="kantoor">123</div>
          </div>
          
          <div  class="someaspcode" onClick="someaspcodethatifyouclickitwilgotothepage">
          <div class="achternaam">jhonny</div>
          <div class="voornaam">depp</div>
          <div class="kantoor">43321</div>
    </div>
       
       

The data from div with id sort comes from a database (thats the reason ,that I show it like this)

What I whant to do is :

If I click on the first icon it shows the list sorted by voornaam(asc) If I click on the second icon it shows the list sorted by voornaam(desc) If I click on the third icon it shows the list sorted by achternaam (asc) and so further

I have tried everything that I found on stackoverflow and google but none of it worked.

Can someone give me a good piece of advice.

what i whant is something like this

http://jsfiddle.net/7sgw21hn/1/

but it must read the content

things i tried

jQuery - Sorting div contents

https://www.sitepoint.com/community/t/sort-div-order-alphabetically-based-on-contents/39955/2

and many more (can't find it right now)

this is before i click

enter image description here

and this is after

enter image description here

can we do something about this

Community
  • 1
  • 1
  • Since you get the data from a database anyway, why not just save the records in an array, use the native array.sort() and then just rerender the table. (aka, use a 'model' as in mvc) – Shilly Sep 27 '16 at 14:12
  • It's decided this way. I work on a team for this project. –  Sep 27 '16 at 14:14
  • It's decided that you have to sort html tags instead of raw data? – Shilly Sep 27 '16 at 14:14
  • that we use div's instead of array –  Sep 27 '16 at 14:16
  • can you use use `data-sort-xxx` attributes similar to the way it is used in that fiddle? make it a little simpler (and quicker) – Jaromanda X Sep 27 '16 at 14:18
  • 'div' is an HTML construct while an array, as @Shilly suggests using, is a functional JavaScript construct that will allow you to accomplish what you are looking to do. If you cannot get the data into an array before it loads on the page, you can at least use JS to screen-scrape the data into an array for sorting purposes. – Dave Cripps Sep 27 '16 at 14:18
  • Apart from it being slow and a terrible design choice imho (the DOM is not a data store), one of the answers you linked should work then. The basic principle is: grab all the nodes from the DOM, parse the div with the classname equal to the field you're sorting out, reorder all the records and then finally change the order in the DOM. But you might as well just do it server side since you use ASP. – Shilly Sep 27 '16 at 14:21
  • Can you explain what you mean by `"but it must read the content"` - does that mean it must read the content inside the DIV when sorting? – AntonB Sep 27 '16 at 14:21
  • voornaam is same as firstname . the content is the firstname it self –  Sep 27 '16 at 14:25
  • if i have zorro - bill - james it must show bill - james - zorro –  Sep 27 '16 at 14:25
  • This is bad html structure, you only need to avoid tables if the data is not tabular - in this case it clearly is so you should use a table - this will benefit in 2 ways. 1 - you can have table headers for your columns / rows meaning the data becomes a whole lot more accessible. 2 - you can use one of the many existing table sorting plugins out there - I like [datatables](https://datatables.net/) as it offers a whole lot of extra functionality on top of the sorting, like filtering, ajax pagination, etc – Pete Sep 27 '16 at 14:31
  • Is it possible to do it the way i whant to do ? –  Sep 27 '16 at 14:33
  • Yes I will write an answer – AntonB Sep 27 '16 at 14:38

2 Answers2

0

Let's give this a try then.

You do have to edit your HTML structure so that each 'record' of first name, last name and office has a seperate container. If you also have to go counting the amout of divs that make up one record, the code grows even larger.

I opted for a list as the wrappers, as it's more or less the standard way. Also added a data-sort attribute to each of the icons so I don't have to go through the hassle of reading the sort type from the header.

<!DOCTYPE html>
<html lang="en">
<head>
    <style>
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    .wrap-3, .wrap-6 {
        border: 1px solid black;
        width: 50%;
    }
    .wrap-3 > * {
        display: inline-block;
        width: 32%;
    }
    .wrap-6 > * {
        display: inline-block;
        width: 16%;
    }
    ul {
        border: 1px solid black;
        list-style: none;
        width: 50%;
    }
    li {
        display: block;
        width: 100%;
    }
    li > * {
        display: inline-block;
        width: 32%;
    }
    </style>
</head>
<body>
    <div class="wrap-3">
        <span class="titel achternaam" >Achternaam</span>
        <span class="titel voornaam" >Voornaam</span>
        <span class="titel kantoor" >Kantoor</span>     
    </div>
    <div id="icons-sort" class="wrap-6">
        <span class="ui-icon ui-icon-circle-triangle-n" data-sort="achternaam-asc">up</span>
        <span class="ui-icon ui-icon-circle-triangle-s" data-sort="achternaam-desc">down</span>
        <span class="ui-icon ui-icon-circle-triangle-n" data-sort="voornaam-asc">up</span>
        <span class="ui-icon ui-icon-circle-triangle-s" data-sort="voornaam-desc">down</span>
        <span class="ui-icon ui-icon-circle-triangle-n" data-sort="kantoor-asc">up</span>
        <span class="ui-icon ui-icon-circle-triangle-s" data-sort="kantoor-desc">down</span>
    </div>
    <ul>
        <li>
            <span class="achternaam">Gates</span>
            <span class="voornaam">Bill</span>
            <span class="kantoor">123</span>
        </li>
        <li>
            <span class="achternaam">Zuckerberg</span>
            <span class="voornaam">Mark</span>
            <span class="kantoor">456</span>
        </li>
        <li>
            <span class="achternaam">Resig</span>
            <span class="voornaam">John</span>
            <span class="kantoor">789</span>
        </li>       
    </ul>
<script>
var clear = function clear( node ) {
    while (node.firstChild) {
        node.removeChild(node.firstChild);
    }
    return node;
};
document.querySelector('#icons-sort').addEventListener('click', function( event ) {
    var list, records, fragment, sortType, field, order;
    if (event.target && event.target.hasAttribute('data-sort')) {
        list = document.querySelector('ul'),
        records = Array.prototype.slice.call(list.querySelectorAll('li')),
        fragment = document.createDocumentFragment(),
        sortType = event.target.getAttribute('data-sort').split('-'),
        field = '.' + sortType[0],
        order = sortType[1];
        records = records.sort(function( first, second ) {
            var firstVal = first.querySelector(field).innerHTML,
                secondVal = second.querySelector(field).innerHTML;
            if (firstVal < secondVal) return -1;
            else if (firstVal > secondVal) return 1;
        });
        if (order === 'desc') records.reverse();
        records.forEach(function( listItem ) {
            fragment.appendChild(listItem);
        });
        clear(list).appendChild(fragment);
    }
});
</script>
</body>
</html>
Shilly
  • 8,511
  • 1
  • 18
  • 24
0

Here's the demo: http://output.jsbin.com/gojopuh

As mentioned, the first two buttons sort asc and desc on first name. The second two buttons sort asc and desc on last name.

My code uses bubble sort and takes advantage of replaceChild for performance benefits.

Also with the code below, adding more controls for this data is now trivial.

Code below, any questions just ask.

var controls = document.querySelectorAll('.spann > span');
var dataContainer = document.querySelector('#sort');
var data = document.querySelectorAll('#sort > div');

// select controls
var ascAchternaam = controls[0];
var descAchternaam = controls[1];
var ascVoornaam = controls[2];
var descVoornaam = controls[3];
var ascKantoor = controls[4];
var descKantoor = controls[5];
var ascVerjaardag = controls[6];
var descVerjaardag = controls[7];

// define a user type
function User(achternaam, voornaam, kantoor, verjaardag, elem) {
  this.achternaam = achternaam;
  this.voornaam = voornaam;
  this.kantoor = kantoor;
  this.verjaardag = verjaardag;
  this.elem = elem;
}

function bubbleSort(order, data, prop) {
  // copy data array
  var sortingArr = Array.prototype.slice.call(data);
  for (var i = sortingArr.length - 1; i >= 0; i--) {
    for (var j = 1; j <= i; j++) {
      var birthdayA = sortingArr[j-1][prop].split('-');
      var birthdayB = sortingArr[j][prop].split('-');

      if (order == 'asc') {
        if (birthdayA.length > 1) {
          if (parseFloat(birthdayA[1], 10) > parseFloat(birthdayB[1], 10) || parseFloat(birthdayA[0], 10) > parseFloat(birthdayB[0], 10)) {
            var temp = sortingArr[j-1]; 
            sortingArr[j-1] = sortingArr[j]; 
            sortingArr[j] = temp;    
          }   
        } else { 
          if (sortingArr[j-1][prop] > sortingArr[j][prop]) {
          var temp = sortingArr[j-1]; 
          sortingArr[j-1] = sortingArr[j]; 
          sortingArr[j] = temp;    
          }     
        }
      } else {
        if (birthdayA.length > 1) {
          if (parseFloat(birthdayA[1], 10) < parseFloat(birthdayB[1], 10) || parseFloat(birthdayA[0], 10) < parseFloat(birthdayB[0], 10)) {
            var temp = sortingArr[j-1]; 
            sortingArr[j-1] = sortingArr[j]; 
            sortingArr[j] = temp;    
          }   
        } else { 
          if (sortingArr[j-1][prop] < sortingArr[j][prop]) {
          var temp = sortingArr[j-1]; 
          sortingArr[j-1] = sortingArr[j]; 
          sortingArr[j] = temp;    
          }     
        }  
      }
    }
  }

  return sortingArr;
}

// event action
function sortOnClick(order, data, prop) {
  var sorted = bubbleSort(order, data, prop);

  for (var i = 0; i < sorted.length; i++) {
    var user = sorted[i]; 
    var wrapper = user.elem.cloneNode(true);
    dataContainer.replaceChild(wrapper, dataContainer.children[i]);
  }

  return sorted; 
}

// used to make the data into a format we need
function formatUsers(data) {
  var userData = [];

  for (var i = 0; i < data.length; i++) {
    var userElem = data[i];
    var fname = userElem.querySelector('.achternaam').textContent;
    var lname = userElem.querySelector('.voornaam').textContent;
    var office = userElem.querySelector('.kantoor').textContent;
    var birthday = userElem.querySelector('.verjaardag').textContent;
    userData.push(new User(fname, lname, office, birthday, userElem));
  }

  return userData;
}

// sorter
function initSorter(data) {
  // reshape our data
  var userData = formatUsers(data);
  // add event listeners to controls
  ascAchternaam.addEventListener('click', function() {
    sortOnClick('asc', userData, 'achternaam');
  });
  descAchternaam.addEventListener('click', function() {
    sortOnClick('desc', userData, 'achternaam');
  });
  ascVoornaam.addEventListener('click', function() {
    sortOnClick('asc', userData, 'voornaam');
  });
  descVoornaam.addEventListener('click', function() {
    sortOnClick('desc', userData, 'voornaam');
  });
  ascKantoor.addEventListener('click', function() {
    sortOnClick('asc', userData, 'kantoor');
  });
  descKantoor.addEventListener('click', function() {
    sortOnClick('desc', userData, 'kantoor');
  });
  ascVerjaardag.addEventListener('click', function() {
    sortOnClick('asc', userData, 'verjaardag');
  });
  descVerjaardag.addEventListener('click', function() {
    sortOnClick('desc', userData, 'verjaardag');
  });
}

// init our sorter
initSorter(data);
AntonB
  • 2,724
  • 1
  • 31
  • 39
  • This works only i have 1 question. the wrapper class is onclick how can i make it work?? so " wrapper.className = 'someaspcode';" that someaspcode is onclick –  Sep 28 '16 at 10:39
  • I have edit my question the last part can we do something about it –  Sep 28 '16 at 14:21
  • you want to add onclick attribute? – AntonB Sep 28 '16 at 15:26
  • I updated my code let me know if that is what you wanted. – AntonB Sep 28 '16 at 15:29
  • I have improved the code to use `cloneNode` which reduces amount of code we write instead of manually creating the elements., also fixes your `onClick` problem. – AntonB Sep 28 '16 at 15:41
  • I have a last question: i have tried to use the header instead of the span var controls = document.querySelectorAll('#Kantoorasp > .KantorenRegel > div'); it works but it only does the desc version is it possible when i click on the kantoor it shows asc and if i click again it shows desc ?? now it only shows desc and stops working –  Sep 29 '16 at 07:56
  • Kantoor is another control, to add that as an option you must select both kantoor asc and kantoor desc buttons. Add event listeners inside `initSorter` and pass in `kantoor` as a prop. – AntonB Sep 29 '16 at 16:19
  • I have added the extra controls to the code as you described. – AntonB Sep 29 '16 at 16:20
  • I see no difference?? what i mean is instead of the span i now use the header. but if i click on the header the sort works but if i click again on the same header it doesnt work. Is it possible that if i click first time it does asc and the second click it will do desc –  Sep 30 '16 at 07:47
  • Can i use 1 header as a controller for asc and desc ( 1 click is asc second click is desc) ? –  Sep 30 '16 at 09:51
  • Yes of course, what your saying Is to toggle with one control both actions right ? – AntonB Sep 30 '16 at 21:51
  • Thnx for your help @AntonB i have fixed my previous question –  Oct 03 '16 at 13:17
  • Glad I could help. – AntonB Oct 03 '16 at 17:14
  • I have added birthdays and it won't sort well. Can u help me with that 1 ? it will only sort at the first number –  Oct 04 '16 at 13:23
  • I get 1-4 and after that 1-7 and after that 10-1 –  Oct 04 '16 at 13:25
  • What is the format of birthday? `mm/dd/yyyy` or something else? – AntonB Oct 04 '16 at 18:14
  • day-month like 1-1 2-1 10-2 –  Oct 05 '16 at 06:55
  • Ok I can write up some code to handle that, because that format is very specific we need to handle that logic. Do you not have the year in birthdays? – AntonB Oct 05 '16 at 15:17
  • The code now includes sorting for birthdays. It's not that pretty, you might want to separate the birthday logic into a function. It sorts by month first and day second. – AntonB Oct 05 '16 at 17:06