1

I have the following table setup:

table {
    border-collapse: collapse;
}

table, th, td {
    border: 1px solid black;
}
<table>
  <thead>
    <tr>
      <th>System Name</th>
      <th>TotalSystemGB</th>
      <th>Drive</th>
      <th>Total GB</th>
      <th>Used GB</th>
      <th>Free GB</th>
    </tr>
  </thead>
  <tbody>
    <tr class="mainRow">
      <td>System 1</td>
      <td>1100</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr class="subRow">
      <td>&nbsp;&nbsp;&nbsp;&nbsp;System 1</td>
      <td></td>
      <td>C:</td>
      <td>100</td>
      <td>50</td>
      <td>50</td>
    </tr>
    <tr class="subRow">
      <td>&nbsp;&nbsp;&nbsp;&nbsp;System 1</td>
      <td></td>
      <td>D:</td>
      <td>1000</td>
      <td>750</td>
      <td>250</td>
    </tr>
    <tr class="mainRow">
      <td>System 2</td>
      <td>820</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr class="subRow">
      <td>&nbsp;&nbsp;&nbsp;&nbsp;System 2</td>
      <td></td>
      <td>C:</td>
      <td>120</td>
      <td>70</td>
      <td>50</td>
    </tr>
    <tr class="subRow">
      <td>&nbsp;&nbsp;&nbsp;&nbsp;System 2</td>
      <td></td>
      <td>D:</td>
      <td>700</td>
      <td>500</td>
      <td>200</td>
    </tr>
    <tr class="mainRow">
      <td>System 3</td>
      <td>3080</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr class="subRow">
      <td>&nbsp;&nbsp;&nbsp;&nbsp;System 3</td>
      <td></td>
      <td>C:</td>
      <td>80</td>
      <td>30</td>
      <td>50</td>
    </tr>
    <tr class="subRow">
      <td>&nbsp;&nbsp;&nbsp;&nbsp;System 3</td>
      <td></td>
      <td>D:</td>
      <td>1000</td>
      <td>750</td>
      <td>250</td>
    </tr>
    <tr class="subRow">
      <td>&nbsp;&nbsp;&nbsp;&nbsp;System 3</td>
      <td></td>
      <td>E:</td>
      <td>2000</td>
      <td>1500</td>
      <td>500</td>
    </tr>
  </tbody
</table>

I would like to have the following behaviour:

  • When sorting on "System Name" and "TotalSystemGB" only the data gets sorted according to mainRows but the subRows remain attached correctly.
  • When sorting on total, used or free GB the subRows get sorted only within the mainRows.

I currently use sortable but I don't see a way to make it work in the way I want it to, especially in regards of keeping the subRows attached to the mainRows.

Is there a clever way to solve this?

3
  • 1
    did you want to stick with vanilla javascript or go with jquery? Commented May 23, 2017 at 6:57
  • 1
    The desired behavior as you are expecting might be easy with advanced frameworks like Extjs. This requirement is very specific so you may have to modify code in the sorttable.js. You can also find the other available resources to achieve this. datatables.net/blog/2017-04-07 tympanus.net/codrops/2009/10/03/… Commented May 23, 2017 at 6:57
  • I tried datatables and it didn't solve my issues. I looked at the sorttable code but quickly gave up as I didn't want to spend a day figuring out how it works internally. I'm currently trying to make it with vanilla JS and use part of the sorttable logic. Commented May 23, 2017 at 7:07

1 Answer 1

2

To sort the main rows, you will need to find the mainRows and their corresponding subRows then basically append them appropriate.

For sub rows, you will also need to find the mainRows but then only append them AFTER their corresponding mainRow.

var last_column;

function get_mains()
{
  var mains = document.querySelectorAll(".mainRow");
  var mains_array = []
  
  mains.forEach( item => mains_array.push(item) );
  return mains_array;
}



function order_mains(column)
{
	var mains_array = get_mains();
 	var table = document.getElementById("body");
  
 	mains_array.sort( function (a, b) {
    let a_text = a.querySelectorAll("td")[column].innerText;
    let b_text = b.querySelectorAll("td")[column].innerText;
    let truthy;
    if (column)
    {
    	return +a_text < +b_text;
    }
    else
    {
    	return a_text.localeCompare(b_text);
    }
  });  
  
  if (last_column === column)
  {
  	mains_array.reverse();
  }

  for (let item of mains_array)
  {
    var siblings = [];
    var sibling = item.nextElementSibling;
    
    table.appendChild(item);
    
    do
    {
      if (sibling.className === "mainRow")
      {
        break;
      }
      siblings.push(sibling);
    }
    while ( sibling = sibling.nextElementSibling);
    
    for (let sib of siblings)
    {
      table.appendChild(sib);
    }
  }
  last_column = (last_column === column) ? -1 : column;
}



function order_subs(column)
{
	var mains_array = get_mains();
  var tbody = document.getElementById("body");
  for (let item of mains_array)
  {
    var siblings = [];
    var sibling = item.nextElementSibling;

    do
    {
      if (sibling.className === "mainRow")
      {
        break;
      }
      siblings.push(sibling);
    }
    while ( sibling = sibling.nextElementSibling);
    
	 	siblings.sort( function (a, b) {
    let a_text = a.querySelectorAll("td")[column].innerText;
    let b_text = b.querySelectorAll("td")[column].innerText;
    return +a_text < +b_text;
 		});     
    
    if (last_column === column)
    {
      siblings.reverse();
    }   
    
    for (let sib of siblings)
    {
      body.insertBefore(sib, item.nextElementSibling);
    }
  }
  last_column = (last_column === column) ? -1 : column;
}
table {
    border-collapse: collapse;
}

table, th, td {
    border: 1px solid black;
}
<table id="the_table">
  <thead>
    <tr>
      <th onclick="order_mains(0)">System Name</th>
      <th onclick="order_mains(1)">TotalSystemGB</th>
      <th>Drive</th>
      <th onclick="order_subs(3)">Total GB</th>
      <th onclick="order_subs(4)">Used GB</th>
      <th onclick="order_subs(5)">Free GB</th>
    </tr>
  </thead>
  <tbody id="body">
    <tr class="mainRow">
      <td>System 1</td>
      <td>1100</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr class="subRow">
      <td>&nbsp;&nbsp;&nbsp;&nbsp;System 1</td>
      <td></td>
      <td>C:</td>
      <td>100</td>
      <td>50</td>
      <td>50</td>
    </tr>
    <tr class="subRow">
      <td>&nbsp;&nbsp;&nbsp;&nbsp;System 1</td>
      <td></td>
      <td>D:</td>
      <td>1000</td>
      <td>750</td>
      <td>250</td>
    </tr>
    <tr class="mainRow">
      <td>System 3</td>
      <td>820</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr class="subRow">
      <td>&nbsp;&nbsp;&nbsp;&nbsp;System 3</td>
      <td></td>
      <td>C:</td>
      <td>120</td>
      <td>70</td>
      <td>50</td>
    </tr>
    <tr class="subRow">
      <td>&nbsp;&nbsp;&nbsp;&nbsp;System 3</td>
      <td></td>
      <td>D:</td>
      <td>700</td>
      <td>500</td>
      <td>200</td>
    </tr>
    <tr class="mainRow">
      <td>System 2</td>
      <td>3080</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr class="subRow">
      <td>&nbsp;&nbsp;&nbsp;&nbsp;System 2</td>
      <td></td>
      <td>C:</td>
      <td>80</td>
      <td>30</td>
      <td>50</td>
    </tr>
    <tr class="subRow">
      <td>&nbsp;&nbsp;&nbsp;&nbsp;System 2</td>
      <td></td>
      <td>D:</td>
      <td>1000</td>
      <td>750</td>
      <td>250</td>
    </tr>
    <tr class="subRow">
      <td>&nbsp;&nbsp;&nbsp;&nbsp;System 2</td>
      <td></td>
      <td>E:</td>
      <td>2000</td>
      <td>1500</td>
      <td>500</td>
    </tr>
  </tbody>
</table>

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

2 Comments

I finally got it to work with a modified version of your answer. Thank you! =) Having to use strict mode for some functions and IE not supporting all functions costed me quite some time... and nerves.
browser support is annoying :\

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.